From de75ec84e295c3f952a200897aa22aa73d7d5867 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期一, 15 十二月 2025 19:37:11 +0800
Subject: [PATCH] 新增了串口割草机拖尾和缩放比例保存功能
---
image/xia10.png | 0
src/gecaoji/Device.java | 24 +++
src/zhuye/LegendDialog.java | 59 +++++++
src/set/Setsys.java | 8
image/xia2.png | 0
src/denglu/UserChuShiHua.java | 1
src/zhuye/MapRenderer.java | 133 ++++++++++++++++
set.properties | 5
image/xia1.png | 0
src/zhuye/Shouye.java | 111 +++++++++++++
src/yaokong/RemoteControlDialog.java | 139 ++++++++--------
image/xia20.png | 0
12 files changed, 398 insertions(+), 82 deletions(-)
diff --git a/image/xia1.png b/image/xia1.png
index 300bfad..7da633b 100644
--- a/image/xia1.png
+++ b/image/xia1.png
Binary files differ
diff --git a/image/xia10.png b/image/xia10.png
index f0d4eaa..9b26e37 100644
--- a/image/xia10.png
+++ b/image/xia10.png
Binary files differ
diff --git a/image/xia2.png b/image/xia2.png
index 9b26e37..f0d4eaa 100644
--- a/image/xia2.png
+++ b/image/xia2.png
Binary files differ
diff --git a/image/xia20.png b/image/xia20.png
index 7da633b..300bfad 100644
--- a/image/xia20.png
+++ b/image/xia20.png
Binary files differ
diff --git a/set.properties b/set.properties
index 432da08..b32ece6 100644
--- a/set.properties
+++ b/set.properties
@@ -1,11 +1,12 @@
-#Serial Port Preferences Updated
-#Mon Dec 15 15:45:14 CST 2025
+#Mower Configuration Properties - Updated
+#Mon Dec 15 19:36:26 CST 2025
appVersion=-1
currentWorkLandNumber=LAND1
cuttingWidth=200
firmwareVersion=-1
handheldMarkerId=
idleTrailDurationSeconds=60
+mapScale=41.66666666666667
mowerId=1234
serialAutoConnect=true
serialBaudRate=115200
diff --git a/src/denglu/UserChuShiHua.java b/src/denglu/UserChuShiHua.java
index 7ba203f..e765f86 100644
--- a/src/denglu/UserChuShiHua.java
+++ b/src/denglu/UserChuShiHua.java
@@ -28,7 +28,6 @@
try (OutputStream output = new FileOutputStream(FILE_PATH)) {
userProperties.store(output, "Updated User Properties");
- System.out.println("灞炴�� " + key + " 宸叉洿鏂颁负: " + value);
} catch (IOException e) {
System.err.println("鏇存柊澶辫触锛屾枃浠跺啓鍏ラ敊璇�: " + e.getMessage());
}
diff --git a/src/gecaoji/Device.java b/src/gecaoji/Device.java
index aa4b77d..fd7cae4 100644
--- a/src/gecaoji/Device.java
+++ b/src/gecaoji/Device.java
@@ -467,6 +467,30 @@
GupdateTime = String.valueOf(System.currentTimeMillis());
updateRelativeCoordinates(latitudeValue, latitudeHemisphere, longitudeValue, longitudeHemisphere);
+
+ // 涓插彛鏀跺埌GNGGA鏁版嵁鍚庯紝瑙﹀彂鎷栧熬鏇存柊
+ notifyMowerTrailUpdate();
+ }
+
+ /**
+ * 閫氱煡鍦板浘娓叉煋鍣ㄦ洿鏂板壊鑽夋満鎷栧熬
+ * 褰撲覆鍙f敹鍒癎NGGA鏁版嵁骞舵洿鏂颁綅缃悗璋冪敤
+ */
+ private void notifyMowerTrailUpdate() {
+ try {
+ // 閫氳繃Shouye.getInstance()鑾峰彇瀹炰緥锛岄伩鍏嶅惊鐜緷璧�
+ zhuye.Shouye shouye = zhuye.Shouye.getInstance();
+ if (shouye != null) {
+ zhuye.MapRenderer mapRenderer = shouye.getMapRenderer();
+ if (mapRenderer != null) {
+ // 璋冪敤鏇存柊鎷栧熬鏂规硶
+ mapRenderer.forceUpdateIdleMowerTrail();
+ }
+ }
+ } catch (Exception e) {
+ // 濡傛灉璋冪敤澶辫触锛岄潤榛樺鐞嗭紙涓嶅奖鍝嶄富瑕佸姛鑳斤級
+ // System.err.println("閫氱煡鎷栧熬鏇存柊澶辫触: " + e.getMessage());
+ }
}
private void updateRelativeCoordinates(String latValue, String latHemisphere,
diff --git a/src/set/Setsys.java b/src/set/Setsys.java
index 2523a0f..7d12a67 100644
--- a/src/set/Setsys.java
+++ b/src/set/Setsys.java
@@ -145,9 +145,12 @@
this.idleTrailDurationSeconds = durationSeconds;
value = String.valueOf(durationSeconds);
break;
+ case "mapScale":
+ // mapScale涓嶉渶瑕佸湪鍐呭瓨涓瓨鍌紝鐩存帴鏇存柊鍒版枃浠�
+ break;
default:
- System.err.println("鏈煡鐨勫睘鎬у悕: " + propertyName);
- return false;
+ // 瀵逛簬鍏朵粬灞炴�э紝涔熷厑璁哥洿鎺ユ洿鏂板埌鏂囦欢锛堜笉鎵撳嵃閿欒锛�
+ break;
}
// 鏇存柊properties鏂囦欢
@@ -173,7 +176,6 @@
// 鍐欏洖鏂囦欢
try (FileOutputStream output = new FileOutputStream(PROPERTIES_FILE)) {
props.store(output, "Mower Configuration Properties - Updated");
- System.out.println("灞炴�� " + propertyName + " 宸叉洿鏂颁负: " + value);
return true;
} catch (IOException e) {
System.err.println("鏇存柊灞炴�ф枃浠跺け璐�: " + e.getMessage());
diff --git a/src/yaokong/RemoteControlDialog.java b/src/yaokong/RemoteControlDialog.java
index 850a14c..ca29763 100644
--- a/src/yaokong/RemoteControlDialog.java
+++ b/src/yaokong/RemoteControlDialog.java
@@ -25,6 +25,9 @@
private Timer steeringControlTimer; // 杞悜鎺у埗瀹氭椂鍣�
private int targetForwardSpeed = 0; // 鐩爣鍓嶈繘/鍚庨��閫熷害
private int targetSteeringSpeed = 0; // 鐩爣杞悜閫熷害
+ // 鐙珛璺熻釜姣忎釜鎽囨潌鐨勫綋鍓嶉�熷害锛岄伩鍏嶇浉浜掑奖鍝�
+ private int independentForwardSpeed = 0; // 鐙珛鐨勫墠杩涢�熷害锛堜笉鍙楄浆鍚戞憞鏉嗗奖鍝嶏級
+ private int independentSteeringSpeed = 0; // 鐙珛鐨勮浆鍚戦�熷害锛堜笉鍙楀墠杩涙憞鏉嗗奖鍝嶏級
private List<JButton> bladeButtons = new ArrayList<>(); // 瀛樺偍鍒�鐩樻帶鍒舵寜閽紝鐢ㄤ簬娓呯悊瀹氭椂鍣�
private String bladeUpDefaultText = "鍒�鐩樺崌"; // 鍒�鐩樺崌鎸夐挳榛樿鏂囧瓧
private String bladeDownDefaultText = "鍒�鐩橀檷"; // 鍒�鐩橀檷鎸夐挳榛樿鏂囧瓧
@@ -158,27 +161,38 @@
moveJoystick.setJoystickListener(new JoystickListener() {
@Override
public void onJoystickMoved(double x, double y) {
- // 鍙娇鐢╕杞存帶鍒跺墠杩涘悗閫�锛屽悜涓婏紙鍖楋級涓烘
- // 璁$畻骞跺洓鑸嶄簲鍏ュ埌鏁存暟閫熷害鍊硷紝姝d负鍓嶈繘锛岃礋涓哄悗閫�
+ // 鍙娇鐢╕杞存帶鍒跺墠杩涘悗閫�
+ // y鍊艰寖鍥达細-1.0锛堝悜涓婏級鍒� 1.0锛堝悜涓嬶級
+ // 璁$畻閫熷害鍊硷細鍚戜笅锛坹>0锛変负鍚庨��锛堣礋鍊硷級锛屽悜涓婏紙y<0锛変负鍓嶈繘锛堟鍊硷級
+ // 鍚庨��鍊艰寖鍥达細0 鍒� -100锛屽墠杩涘�艰寖鍥达細0 鍒� 100
int forwardVal = (int) Math.round(-y * 100.0);
// 闄愬埗鍦� [-100, 100]
forwardVal = Math.max(-100, Math.min(100, forwardVal));
- // 鏇存柊鐩爣閫熷害
- targetForwardSpeed = forwardVal;
-
- if (Math.abs(y) > 0.1) {
- // 鎽囨潌涓嶅湪涓績浣嶇疆锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
- startForwardControlTimer();
- } else {
- // 鎽囨潌鍥炲埌涓績浣嶇疆锛屽仠姝㈠彂閫�
- stopForwardControlTimer();
- stopForward();
+ // 姝诲尯澶勭悊锛氬鏋滈�熷害鍊煎湪-10鍒�10涔嬮棿锛岃涓�0锛堥伩鍏嶅井灏忔姈鍔級
+ if (Math.abs(forwardVal) <= 10) {
+ forwardVal = 0;
}
- // 鏇存柊椤堕儴鏄剧ず锛堢Щ鍔ㄦ樉绀哄綋鍓嶅墠杩�/鍚庨��閫熷害锛岃浆鍚戝彇褰撳墠杞悜閫熷害浣滀负鍙傝�冿級
- int steeringVal = Control03.getCurrentSteeringSpeed();
- updateJoystickValues(forwardVal, steeringVal);
+ // 鏇存柊鐩爣閫熷害鍜岀嫭绔嬮�熷害
+ targetForwardSpeed = forwardVal;
+ independentForwardSpeed = forwardVal;
+
+ if (forwardVal != 0) {
+ // 鎽囨潌涓嶅湪姝诲尯锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
+ // 鍚庨��鏃� forwardVal 涓鸿礋鍊硷紙-100鍒�-11锛夛紝鍓嶈繘鏃� forwardVal 涓烘鍊硷紙11鍒�100锛�
+ startForwardControlTimer();
+ } else {
+ // 鎽囨潌鍦ㄦ鍖烘垨涓績浣嶇疆锛屽仠姝㈠畾鏃跺櫒
+ stopForwardControlTimer();
+ // 灏嗙嫭绔嬬殑鍓嶈繘閫熷害璁剧疆涓�0
+ independentForwardSpeed = 0;
+ // 鍙戦�佸仠姝㈡寚浠わ紙淇濇寔杞悜閫熷害涓嶅彉锛�
+ Control03.setAndSendSpeeds(independentSteeringSpeed, 0);
+ }
+
+ // 鏇存柊椤堕儴鏄剧ず锛堜娇鐢ㄧ嫭绔嬬殑閫熷害鍊硷級
+ updateJoystickValues(forwardVal, independentSteeringSpeed);
}
});
// 杞悜鎽囨潌锛堣摑鑹蹭富棰橈級
@@ -187,26 +201,37 @@
turnJoystick.setJoystickListener(new JoystickListener() {
@Override
public void onJoystickMoved(double x, double y) {
- // 鍙娇鐢╔杞存帶鍒跺乏鍙宠浆鍚戯紝鍚戝彸涓烘
- // 璁$畻骞跺洓鑸嶄簲鍏ュ埌鏁存暟杞悜鍊硷紝姝d负鍙宠浆锛岃礋涓哄乏杞�
+ // 鍙娇鐢╔杞存帶鍒跺乏鍙宠浆鍚�
+ // x鍊艰寖鍥达細-1.0锛堝悜宸︼級鍒� 1.0锛堝悜鍙筹級
+ // 璁$畻杞悜鍊硷細鍚戝乏锛坸<0锛変负宸﹁浆锛堣礋鍊硷級锛屽悜鍙筹紙x>0锛変负鍙宠浆锛堟鍊硷級
+ // 宸﹁浆鍊艰寖鍥达細0 鍒� -100锛屽彸杞�艰寖鍥达細0 鍒� 100
int steeringVal = (int) Math.round(x * 100.0);
steeringVal = Math.max(-100, Math.min(100, steeringVal));
- // 鏇存柊鐩爣閫熷害
- targetSteeringSpeed = steeringVal;
-
- if (Math.abs(x) > 0.1) {
- // 鎽囨潌涓嶅湪涓績浣嶇疆锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
- startSteeringControlTimer();
- } else {
- // 鎽囨潌鍥炲埌涓績浣嶇疆锛屽仠姝㈠彂閫�
- stopSteeringControlTimer();
- stopSteering();
+ // 姝诲尯澶勭悊锛氬鏋滈�熷害鍊煎湪-10鍒�10涔嬮棿锛岃涓�0锛堥伩鍏嶅井灏忔姈鍔級
+ if (Math.abs(steeringVal) <= 10) {
+ steeringVal = 0;
}
- // 鏇存柊椤堕儴鏄剧ず锛堣浆鍚戞樉绀哄綋鍓嶈浆鍚戦�熷害锛岀Щ鍔ㄦ樉绀哄綋鍓嶅墠杩涢�熷害锛�
- int forwardVal = Control03.getCurrentForwardSpeed();
- updateJoystickValues(forwardVal, steeringVal);
+ // 鏇存柊鐩爣閫熷害鍜岀嫭绔嬮�熷害
+ targetSteeringSpeed = steeringVal;
+ independentSteeringSpeed = steeringVal;
+
+ if (steeringVal != 0) {
+ // 鎽囨潌涓嶅湪姝诲尯锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
+ // 宸﹁浆鏃� steeringVal 涓鸿礋鍊硷紙-100鍒�-11锛夛紝鍙宠浆鏃� steeringVal 涓烘鍊硷紙11鍒�100锛�
+ startSteeringControlTimer();
+ } else {
+ // 鎽囨潌鍦ㄦ鍖烘垨涓績浣嶇疆锛屽仠姝㈠畾鏃跺櫒
+ stopSteeringControlTimer();
+ // 灏嗙嫭绔嬬殑杞悜閫熷害璁剧疆涓�0
+ independentSteeringSpeed = 0;
+ // 鍙戦�佸仠姝㈡寚浠わ紙淇濇寔鍓嶈繘閫熷害涓嶅彉锛�
+ Control03.setAndSendSpeeds(0, independentForwardSpeed);
+ }
+
+ // 鏇存柊椤堕儴鏄剧ず锛堜娇鐢ㄧ嫭绔嬬殑閫熷害鍊硷級
+ updateJoystickValues(independentForwardSpeed, steeringVal);
}
});
joystickPanel.add(moveJoystick);
@@ -625,14 +650,9 @@
}
private void stopForward() {
- if (Control03.getCurrentForwardSpeed() != 0) {
- boolean success = Control03.approachForwardSpeedToZero(20);
- if (!success) {
- showSerialClosedWarning();
- return;
- }
- serialWarningShown = false;
- }
+ // 灏嗙嫭绔嬬殑鍓嶈繘閫熷害璁剧疆涓�0锛屼繚鎸佽浆鍚戦�熷害涓嶅彉
+ independentForwardSpeed = 0;
+ Control03.setAndSendSpeeds(independentSteeringSpeed, 0);
}
private void applySteeringSpeed(int speed) {
@@ -655,14 +675,9 @@
}
private void stopSteering() {
- if (Control03.getCurrentSteeringSpeed() != 0) {
- boolean success = Control03.approachSteeringSpeedToZero(25);
- if (!success) {
- showSerialClosedWarning();
- return;
- }
- serialWarningShown = false;
- }
+ // 灏嗙嫭绔嬬殑杞悜閫熷害璁剧疆涓�0锛屼繚鎸佸墠杩涢�熷害涓嶅彉
+ independentSteeringSpeed = 0;
+ Control03.setAndSendSpeeds(0, independentForwardSpeed);
}
/**
@@ -729,36 +744,24 @@
* 鎸佺画鍙戦�佸墠杩�/鍚庨��閫熷害鎸囦护
*/
private void applyForwardSpeedContinuously(int targetSpeed) {
- int currentSpeed = Control03.getCurrentForwardSpeed();
- int currentSteeringSpeed = Control03.getCurrentSteeringSpeed();
+ // 鏇存柊鐙珛鐨勫墠杩涢�熷害
+ independentForwardSpeed = targetSpeed;
- // 濡傛灉宸茬粡杈惧埌鐩爣閫熷害锛岀洿鎺ュ彂閫佷竴娆′互淇濇寔鐘舵��
- if (currentSpeed == targetSpeed) {
- // 鐩存帴鍙戦�佺洰鏍囬�熷害鎸囦护浠ヤ繚鎸佺姸鎬侊紙鍗充娇閫熷害鐩稿悓涔熻鍙戦�侊級
- Control03.setAndSendSpeeds(currentSteeringSpeed, targetSpeed);
- } else {
- // 閫愭璋冩暣鍒扮洰鏍囬�熷害
- int delta = targetSpeed > currentSpeed ? 10 : -10;
- Control03.adjustForwardSpeed(delta);
- }
+ // 浣跨敤鐙珛鐨勮浆鍚戦�熷害锛堜笉鍙楀墠杩涙憞鏉嗗奖鍝嶏級锛屽彧鏇存柊鍓嶈繘閫熷害
+ // 杩欐牱鍓嶈繘鎽囨潌鐨勬搷浣滀笉浼氬奖鍝嶈浆鍚戦�熷害
+ Control03.setAndSendSpeeds(independentSteeringSpeed, independentForwardSpeed);
}
/**
* 鎸佺画鍙戦�佽浆鍚戦�熷害鎸囦护
*/
private void applySteeringSpeedContinuously(int targetSpeed) {
- int currentSpeed = Control03.getCurrentSteeringSpeed();
- int currentForwardSpeed = Control03.getCurrentForwardSpeed();
+ // 鏇存柊鐙珛鐨勮浆鍚戦�熷害
+ independentSteeringSpeed = targetSpeed;
- // 濡傛灉宸茬粡杈惧埌鐩爣閫熷害锛岀洿鎺ュ彂閫佷竴娆′互淇濇寔鐘舵��
- if (currentSpeed == targetSpeed) {
- // 鐩存帴鍙戦�佺洰鏍囬�熷害鎸囦护浠ヤ繚鎸佺姸鎬侊紙鍗充娇閫熷害鐩稿悓涔熻鍙戦�侊級
- Control03.setAndSendSpeeds(targetSpeed, currentForwardSpeed);
- } else {
- // 閫愭璋冩暣鍒扮洰鏍囬�熷害
- int delta = targetSpeed > currentSpeed ? 15 : -15;
- Control03.adjustSteeringSpeed(delta);
- }
+ // 浣跨敤鐙珛鐨勫墠杩涢�熷害锛堜笉鍙楄浆鍚戞憞鏉嗗奖鍝嶏級锛屽彧鏇存柊杞悜閫熷害
+ // 杩欐牱杞悜鎽囨潌鐨勬搷浣滀笉浼氬奖鍝嶅墠杩涢�熷害
+ Control03.setAndSendSpeeds(independentSteeringSpeed, independentForwardSpeed);
}
// 鏇存柊椤堕儴鏄剧ず鐨勬憞鏉嗘暟鍊硷紙鍦� EDT 涓婅皟鐢級锛屾枃瀛楁牴鎹暟鍊兼槧灏勪负鏂瑰悜鎻忚堪
diff --git a/src/zhuye/LegendDialog.java b/src/zhuye/LegendDialog.java
index d595034..7469b67 100644
--- a/src/zhuye/LegendDialog.java
+++ b/src/zhuye/LegendDialog.java
@@ -32,6 +32,29 @@
mainPanel.setBackground(Color.WHITE);
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 10, 15));
+ // 璁$畻鍥句緥鍐呭闈㈡澘鐨勫搴︼紙鐢ㄤ簬璁剧疆鍥炬爣灏哄锛�
+ // 鍥句緥瀵硅瘽妗嗗搴� = DIALOG_WIDTH * 0.8
+ // 涓婚潰鏉垮乏鍙宠竟妗嗗悇15鍍忕礌锛屽浘渚嬪唴瀹归潰鏉垮乏鍙冲唴杈硅窛鍚�10鍍忕礌
+ int adjustedWidth = (int) Math.round(UIConfig.DIALOG_WIDTH * 0.8);
+ int iconSize = adjustedWidth - 30 - 20; // 鍑忓幓涓婚潰鏉垮乏鍙宠竟妗�(15*2)鍜屽浘渚嬪唴瀹归潰鏉垮乏鍙冲唴杈硅窛(10*2)
+
+ // 鍒涘缓鍓茶崏鏈哄浘鏍囬潰鏉�
+ JPanel iconPanel = new JPanel(new BorderLayout());
+ iconPanel.setBackground(Color.WHITE);
+ iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); // 搴曢儴闂磋窛10鍍忕礌
+
+ JLabel gecaojiLabel = new JLabel();
+ gecaojiLabel.setHorizontalAlignment(SwingConstants.CENTER);
+ ImageIcon gecaojiIcon = loadIcon("image/gecaoji.png", iconSize, iconSize);
+ if (gecaojiIcon != null) {
+ gecaojiLabel.setIcon(gecaojiIcon);
+ } else {
+ // 濡傛灉鍥炬爣鍔犺浇澶辫触锛屾樉绀哄崰浣嶆枃鏈�
+ gecaojiLabel.setText("鍓茶崏鏈哄浘鏍�");
+ gecaojiLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+ }
+ iconPanel.add(gecaojiLabel, BorderLayout.CENTER);
+
// 鍥句緥鍐呭闈㈡澘 - 鐩存帴娣诲姞锛屼笉浣跨敤婊氬姩鏉�
JPanel contentPanel = new JPanel();
contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
@@ -61,7 +84,8 @@
contentPanel.remove(contentPanel.getComponentCount() - 1);
}
- // 鐩存帴娣诲姞鍐呭闈㈡澘锛屼笉浣跨敤婊氬姩鏉�
+ // 娣诲姞鍥炬爣闈㈡澘鍜屽浘渚嬪唴瀹归潰鏉�
+ mainPanel.add(iconPanel, BorderLayout.NORTH);
mainPanel.add(contentPanel, BorderLayout.CENTER);
getContentPane().add(mainPanel);
@@ -154,4 +178,37 @@
return itemPanel;
}
+
+ /**
+ * 鍔犺浇骞剁缉鏀惧浘鏍�
+ * @param iconPath 鍥炬爣璺緞
+ * @param width 鐩爣瀹藉害
+ * @param height 鐩爣楂樺害
+ * @return 缂╂斁鍚庣殑鍥炬爣
+ */
+ private ImageIcon loadIcon(String iconPath, int width, int height) {
+ try {
+ java.net.URL imgURL = getClass().getClassLoader().getResource(iconPath);
+ if (imgURL == null) {
+ // 灏濊瘯浠庢枃浠剁郴缁熷姞杞�
+ java.io.File imgFile = new java.io.File(iconPath);
+ if (imgFile.exists()) {
+ ImageIcon originalIcon = new ImageIcon(imgFile.getAbsolutePath());
+ Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
+ ImageIcon scaledIcon = new ImageIcon(scaledImage);
+ scaledIcon.setDescription(iconPath);
+ return scaledIcon;
+ }
+ } else {
+ ImageIcon originalIcon = new ImageIcon(imgURL);
+ Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
+ ImageIcon scaledIcon = new ImageIcon(scaledImage);
+ scaledIcon.setDescription(iconPath);
+ return scaledIcon;
+ }
+ } catch (Exception e) {
+ System.err.println("鏃犳硶鍔犺浇鍥炬爣: " + iconPath + " - " + e.getMessage());
+ }
+ return null;
+ }
}
\ No newline at end of file
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 635a1b1..8083749 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Set;
+import set.Setsys;
import gecaoji.Device;
import gecaoji.Gecaoji;
import gecaoji.GecaojiMeg;
@@ -35,13 +36,15 @@
*/
public class MapRenderer {
// 瑙嗗浘鍙樻崲鍙傛暟
- private double scale = 1.0;
+ private static final double DEFAULT_SCALE = 20.0; // 榛樿缂╂斁姣斾緥
+ private double scale = DEFAULT_SCALE;
private double translateX = 0.0;
private double translateY = 0.0;
private Point lastDragPoint;
private static final double MIN_SCALE = 0.05d;
private static final double MAX_SCALE = 50.0d;
private static final double SCALE_EPSILON = 1e-6d;
+ private static final String MAP_SCALE_PROPERTY = "mapScale"; // 灞炴�ф枃浠朵腑鐨勯敭鍚�
// 涓婚棰滆壊
private final Color THEME_COLOR = new Color(46, 139, 87);
@@ -111,6 +114,40 @@
this.mowerUpdateTimer = createMowerTimer();
this.mowerInfoManager = new GecaojiMeg(visualizationPanel, mower);
setupMouseListeners();
+ // 浠庨厤缃枃浠惰鍙栦笂娆′繚瀛樼殑缂╂斁姣斾緥
+ loadScaleFromProperties();
+ }
+
+ /**
+ * 浠庨厤缃枃浠惰鍙栫缉鏀炬瘮渚�
+ */
+ private void loadScaleFromProperties() {
+ String scaleValue = Setsys.getPropertyValue(MAP_SCALE_PROPERTY);
+ if (scaleValue != null && !scaleValue.trim().isEmpty()) {
+ try {
+ double savedScale = Double.parseDouble(scaleValue.trim());
+ // 楠岃瘉缂╂斁姣斾緥鏄惁鍦ㄦ湁鏁堣寖鍥村唴
+ if (savedScale >= MIN_SCALE && savedScale <= MAX_SCALE) {
+ scale = savedScale;
+ } else {
+ scale = DEFAULT_SCALE;
+ }
+ } catch (NumberFormatException e) {
+ // 濡傛灉瑙f瀽澶辫触锛屼娇鐢ㄩ粯璁ゅ��
+ scale = DEFAULT_SCALE;
+ }
+ } else {
+ // 濡傛灉娌℃湁淇濆瓨鐨勫�硷紝浣跨敤榛樿鍊�
+ scale = DEFAULT_SCALE;
+ }
+ }
+
+ /**
+ * 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ */
+ private void saveScaleToProperties() {
+ Setsys setsys = new Setsys();
+ setsys.updateProperty(MAP_SCALE_PROPERTY, String.valueOf(scale));
}
/**
@@ -218,6 +255,8 @@
translateX += (newWorldX - worldX);
translateY += (newWorldY - worldY);
+ // 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ saveScaleToProperties();
visualizationPanel.repaint();
}
@@ -253,9 +292,11 @@
* 閲嶇疆瑙嗗浘
*/
public void resetView() {
- scale = 1.0;
+ scale = DEFAULT_SCALE;
translateX = 0.0;
translateY = 0.0;
+ // 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ saveScaleToProperties();
visualizationPanel.repaint();
}
@@ -482,7 +523,8 @@
if (device == null) {
return;
}
- if (!isHighPrecisionFix(device.getPositioningStatus())) {
+ // 浣跨敤鏇村鏉剧殑瀹氫綅鐘舵�佸垽鏂紝鍏佽鐘舵��1鍜�4鏄剧ず鎷栧熬
+ if (!isValidFixForTrail(device.getPositioningStatus())) {
return;
}
@@ -504,6 +546,56 @@
idleMowerTrail.addLast(new tuowei.TrailSample(now, new Point2D.Double(position.x, position.y)));
pruneIdleMowerTrail(now);
}
+
+ /**
+ * 寮哄埗鏇存柊鎷栧熬锛堢敤浜庢敹鍒�$GNGGA鏁版嵁鏃剁珛鍗虫洿鏂帮級
+ * 杩欎釜鏂规硶浼氬埛鏂癿ower浣嶇疆骞剁珛鍗虫坊鍔犲埌鎷栧熬
+ */
+ public void forceUpdateIdleMowerTrail() {
+ long now = System.currentTimeMillis();
+ pruneIdleMowerTrail(now);
+
+ if (idleTrailSuppressed || realtimeTrackRecording) {
+ if (!idleMowerTrail.isEmpty()) {
+ clearIdleMowerTrail();
+ }
+ return;
+ }
+
+ Device device = Device.getGecaoji();
+ if (device == null) {
+ return;
+ }
+ // 浣跨敤鏇村鏉剧殑瀹氫綅鐘舵�佸垽鏂紝鍏佽鐘舵��1鍜�4鏄剧ず鎷栧熬
+ if (!isValidFixForTrail(device.getPositioningStatus())) {
+ return;
+ }
+
+ // 鍒锋柊mower浣嶇疆锛屼娇鐢ㄦ渶鏂扮殑Device鏁版嵁
+ mower.refreshFromDevice();
+ Point2D.Double position = mower.getPosition();
+ if (position == null || !Double.isFinite(position.x) || !Double.isFinite(position.y)) {
+ return;
+ }
+
+ tuowei.TrailSample lastSample = idleMowerTrail.peekLast();
+ if (lastSample != null) {
+ Point2D.Double lastPoint = lastSample.getPoint();
+ double dx = position.x - lastPoint.x;
+ double dy = position.y - lastPoint.y;
+ if (Math.hypot(dx, dy) < IDLE_TRAIL_SAMPLE_DISTANCE_METERS) {
+ return;
+ }
+ }
+
+ idleMowerTrail.addLast(new tuowei.TrailSample(now, new Point2D.Double(position.x, position.y)));
+ pruneIdleMowerTrail(now);
+
+ // 绔嬪嵆閲嶇粯锛岀‘淇濇嫋灏惧強鏃舵樉绀�
+ if (visualizationPanel != null) {
+ visualizationPanel.repaint();
+ }
+ }
private void pruneIdleMowerTrail(long now) {
if (idleMowerTrail.isEmpty()) {
@@ -1233,6 +1325,31 @@
return false;
}
}
+
+ /**
+ * 鍒ゆ柇瀹氫綅鐘舵�佹槸鍚︽湁鏁堬紝鍙敤浜庢樉绀烘嫋灏�
+ * 鎺ュ彈鐘舵��1锛堝崟鐐瑰畾浣嶏級鍜�4锛堝浐瀹氳В锛�
+ */
+ private boolean isValidFixForTrail(String fixQuality) {
+ if (fixQuality == null) {
+ return false;
+ }
+ String trimmed = fixQuality.trim();
+ if (trimmed.isEmpty()) {
+ return false;
+ }
+ // 鎺ュ彈鐘舵��1锛堝崟鐐瑰畾浣嶏級鍜�4锛堝浐瀹氳В锛�
+ if ("1".equals(trimmed) || "4".equals(trimmed)) {
+ return true;
+ }
+ try {
+ double value = Double.parseDouble(trimmed);
+ // 鎺ュ彈1.0鎴�4.0
+ return Math.abs(value - 1.0d) < 1e-6 || Math.abs(value - 4.0d) < 1e-6;
+ } catch (NumberFormatException ex) {
+ return false;
+ }
+ }
private boolean isPointInsideActiveBoundary(Point2D.Double point) {
if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) {
@@ -1339,7 +1456,15 @@
* 璁剧疆瑙嗗浘鍙樻崲鍙傛暟锛堢敤浜庣▼搴忓寲鎺у埗锛�
*/
public void setViewTransform(double scale, double translateX, double translateY) {
- this.scale = scale;
+ // 闄愬埗缂╂斁鑼冨洿
+ scale = Math.max(MIN_SCALE, Math.min(scale, MAX_SCALE));
+ // 濡傛灉缂╂斁姣斾緥鏀瑰彉浜嗭紝淇濆瓨鍒伴厤缃枃浠�
+ if (Math.abs(this.scale - scale) > SCALE_EPSILON) {
+ this.scale = scale;
+ saveScaleToProperties();
+ } else {
+ this.scale = scale;
+ }
this.translateX = translateX;
this.translateY = translateY;
visualizationPanel.repaint();
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index 29a287f..7d78ab2 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -91,10 +91,20 @@
private Sets settingsDialog;
private BaseStation baseStation;
- private final Consumer<String> serialLineListener = line -> SwingUtilities.invokeLater(this::updateDataPacketCountLabel);
-
// 鍦板浘娓叉煋鍣�
private MapRenderer mapRenderer;
+
+ private final Consumer<String> serialLineListener = line -> {
+ SwingUtilities.invokeLater(() -> {
+ updateDataPacketCountLabel();
+ // 濡傛灉鏀跺埌$GNGGA鏁版嵁锛岀珛鍗虫洿鏂版嫋灏�
+ if (line != null && line.trim().startsWith("$GNGGA")) {
+ if (mapRenderer != null) {
+ mapRenderer.forceUpdateIdleMowerTrail();
+ }
+ }
+ });
+ };
private static final int FLOAT_ICON_SIZE = 32;
private JButton endDrawingButton;
private JButton drawingPauseButton;
@@ -208,12 +218,42 @@
SwingUtilities.invokeLater(() -> {
Shouye.this.checkIdentifiersAndPromptIfNeeded();
Shouye.this.showInitialMowerSelfCheckDialogIfNeeded();
+ // 璁剧疆绐楀彛鍏抽棴鐩戝惉鍣紝鍦ㄥ叧闂椂淇濆瓨缂╂斁姣斾緥
+ setupWindowCloseListener();
});
}
}
};
addHierarchyListener(listener);
}
+
+ /**
+ * 璁剧疆绐楀彛鍏抽棴鐩戝惉鍣紝鍦ㄧ獥鍙e叧闂椂淇濆瓨褰撳墠缂╂斁姣斾緥
+ */
+ private void setupWindowCloseListener() {
+ Window window = SwingUtilities.getWindowAncestor(this);
+ if (window != null && window instanceof JFrame) {
+ JFrame frame = (JFrame) window;
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ // 淇濆瓨褰撳墠缂╂斁姣斾緥
+ saveCurrentScale();
+ }
+ });
+ }
+ }
+
+ /**
+ * 淇濆瓨褰撳墠鍦板浘缂╂斁姣斾緥鍒伴厤缃枃浠�
+ */
+ public void saveCurrentScale() {
+ if (mapRenderer != null) {
+ double currentScale = mapRenderer.getScale();
+ Setsys setsys = new Setsys();
+ setsys.updateProperty("mapScale", String.valueOf(currentScale));
+ }
+ }
private void showInitialMowerSelfCheckDialogIfNeeded() {
// 宸茬Щ闄よ繘鍏ヤ富椤垫椂鐨勮嚜妫�鎻愮ず锛堟寜鐢ㄦ埛瑕佹眰鍒犻櫎锛�
@@ -352,6 +392,37 @@
// 鍙鍖栧尯鍩� - 浣跨敤MapRenderer杩涜缁樺埗
visualizationPanel = new JPanel() {
+ private ImageIcon gecaojiIcon = null;
+ private static final int GECAOJI_ICON_X = 37;
+ private static final int GECAOJI_ICON_Y = 10;
+ private static final int GECAOJI_ICON_SIZE = 20;
+
+ {
+ // 鍔犺浇鍓茶崏鏈哄浘鏍囷紝澶у皬20x20鍍忕礌
+ gecaojiIcon = loadScaledIcon("image/gecaoji.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE);
+ // 鍚敤宸ュ叿鎻愮ず
+ setToolTipText("");
+ }
+
+ /**
+ * 妫�鏌ラ紶鏍囦綅缃槸鍚﹀湪鍓茶崏鏈哄浘鏍囧尯鍩熷唴
+ */
+ private boolean isMouseOnGecaojiIcon(Point mousePoint) {
+ return mousePoint.x >= GECAOJI_ICON_X &&
+ mousePoint.x <= GECAOJI_ICON_X + GECAOJI_ICON_SIZE &&
+ mousePoint.y >= GECAOJI_ICON_Y &&
+ mousePoint.y <= GECAOJI_ICON_Y + GECAOJI_ICON_SIZE;
+ }
+
+ @Override
+ public String getToolTipText(MouseEvent event) {
+ // 濡傛灉榧犳爣鍦ㄥ壊鑽夋満鍥炬爣鍖哄煙鍐咃紝鏄剧ず鎻愮ず鏂囧瓧
+ if (isMouseOnGecaojiIcon(event.getPoint())) {
+ return "浠ュ壊鑽夋満涓轰腑蹇�";
+ }
+ return super.getToolTipText(event);
+ }
+
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -359,14 +430,48 @@
if (mapRenderer != null) {
mapRenderer.renderMap(g);
}
+ // 鍦ㄥ湴鍥惧乏涓婅缁樺埗鍓茶崏鏈哄浘鏍�
+ // 姘村钩鏂瑰悜涓庨�熷害鎸囩ず鍣ㄥ榻愶紙x=37锛�
+ // 鍨傜洿鏂瑰悜涓庡崼鏄熺姸鎬佸浘鏍囧榻愶紙y=10锛岄�熷害鎸囩ず鍣ㄩ潰鏉块《閮ㄨ竟璺�10鍍忕礌锛屼娇鍥炬爣涓績瀵归綈锛�
+ if (gecaojiIcon != null) {
+ g.drawImage(gecaojiIcon.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null);
+ }
}
};
visualizationPanel.setLayout(new BorderLayout());
+
+ // 娣诲姞榧犳爣鐐瑰嚮鐩戝惉鍣紝妫�娴嬫槸鍚︾偣鍑讳簡鍓茶崏鏈哄浘鏍�
+ visualizationPanel.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (SwingUtilities.isLeftMouseButton(e)) {
+ Point clickPoint = e.getPoint();
+ // 妫�鏌ユ槸鍚︾偣鍑讳簡鍓茶崏鏈哄浘鏍囧尯鍩燂紙37, 10, 20, 20锛�
+ if (clickPoint.x >= 37 && clickPoint.x <= 57 &&
+ clickPoint.y >= 10 && clickPoint.y <= 30) {
+ // 鐐瑰嚮浜嗗壊鑽夋満鍥炬爣锛屽皢鍦板浘瑙嗗浘涓績绉诲姩鍒板壊鑽夋満浣嶇疆
+ if (mapRenderer != null) {
+ Gecaoji mower = mapRenderer.getMower();
+ if (mower != null && mower.hasValidPosition()) {
+ Point2D.Double mowerPosition = mower.getPosition();
+ if (mowerPosition != null) {
+ // 鑾峰彇褰撳墠缂╂斁姣斾緥
+ double currentScale = mapRenderer.getScale();
+ // 璁剧疆瑙嗗浘鍙樻崲锛屼娇鍓茶崏鏈轰綅缃搴斿埌灞忓箷涓績
+ // translateX = -mowerX, translateY = -mowerY 鍙互璁╁壊鑽夋満鍦ㄥ睆骞曚腑蹇�
+ mapRenderer.setViewTransform(currentScale, -mowerPosition.x, -mowerPosition.y);
+ }
+ }
+ }
+ }
+ }
+ }
+ });
JPanel speedIndicatorPanel = createSpeedIndicatorPanel();
visualizationPanel.add(speedIndicatorPanel, BorderLayout.NORTH);
- // 鍒涘缓鍔熻兘鎸夐挳闈㈡澘锛堟斁鍦ㄥ乏涓婅锛�
+ // 鍒涘缓鍔熻兘鎸夐挳闈㈡澘
JPanel functionButtonsPanel = new JPanel();
functionButtonsPanel.setLayout(new BoxLayout(functionButtonsPanel, BoxLayout.Y_AXIS));
functionButtonsPanel.setOpaque(false);
--
Gitblit v1.10.0