From f784463ab019c1113cf0b31a249e8802b07a57fa Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 16 十二月 2025 15:26:15 +0800
Subject: [PATCH] 保存地图最后位置
---
src/zhuye/MapRenderer.java | 305 ++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 253 insertions(+), 52 deletions(-)
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 4562a15..8406d2b 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;
@@ -28,17 +29,22 @@
import zhangaiwu.Obstacledraw;
import zhangaiwu.Obstacledge;
import zhangaiwu.yulanzhangaiwu;
+import yaokong.Control03;
/**
* 鍦板浘娓叉煋鍣� - 璐熻矗鍧愭爣绯荤粯鍒躲�佽鍥惧彉鎹㈢瓑鍔熻兘
*/
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 Point mousePoint;
+ 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);
@@ -100,6 +106,7 @@
public static final int DEFAULT_IDLE_TRAIL_DURATION_SECONDS = 60;
private static final double IDLE_TRAIL_SAMPLE_DISTANCE_METERS = 0.05d;
private long idleTrailDurationMs = DEFAULT_IDLE_TRAIL_DURATION_SECONDS * 1_000L;
+ private static final double ZOOM_STEP_FACTOR = 1.2d;
public MapRenderer(JPanel visualizationPanel) {
this.visualizationPanel = visualizationPanel;
@@ -107,6 +114,64 @@
this.mowerUpdateTimer = createMowerTimer();
this.mowerInfoManager = new GecaojiMeg(visualizationPanel, mower);
setupMouseListeners();
+ // 浠庨厤缃枃浠惰鍙栦笂娆′繚瀛樼殑缂╂斁姣斾緥鍜岃鍥句腑蹇冨潗鏍�
+ loadViewSettingsFromProperties();
+ }
+
+ /**
+ * 浠庨厤缃枃浠惰鍙栫缉鏀炬瘮渚嬪拰瑙嗗浘涓績鍧愭爣
+ */
+ private void loadViewSettingsFromProperties() {
+ // 鍔犺浇缂╂斁姣斾緥
+ 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;
+ }
+
+ // 鍔犺浇瑙嗗浘涓績鍧愭爣
+ String viewCenterXValue = Setsys.getPropertyValue("viewCenterX");
+ String viewCenterYValue = Setsys.getPropertyValue("viewCenterY");
+ if (viewCenterXValue != null && !viewCenterXValue.trim().isEmpty()) {
+ try {
+ translateX = Double.parseDouble(viewCenterXValue.trim());
+ } catch (NumberFormatException e) {
+ translateX = 0.0;
+ }
+ } else {
+ translateX = 0.0;
+ }
+ if (viewCenterYValue != null && !viewCenterYValue.trim().isEmpty()) {
+ try {
+ translateY = Double.parseDouble(viewCenterYValue.trim());
+ } catch (NumberFormatException e) {
+ translateY = 0.0;
+ }
+ } else {
+ translateY = 0.0;
+ }
+ }
+
+ /**
+ * 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ */
+ private void saveScaleToProperties() {
+ Setsys setsys = new Setsys();
+ // 淇濈暀2浣嶅皬鏁�
+ setsys.updateProperty(MAP_SCALE_PROPERTY, String.format("%.2f", scale));
}
/**
@@ -115,10 +180,10 @@
private void setupMouseListeners() {
// 榧犳爣婊氳疆缂╂斁
visualizationPanel.addMouseWheelListener(e -> {
- mousePoint = e.getPoint();
+ Point referencePoint = e.getPoint();
int notches = e.getWheelRotation();
- double zoomFactor = notches < 0 ? 1.2 : 1/1.2;
- zoomAtPoint(zoomFactor);
+ double zoomFactor = notches < 0 ? ZOOM_STEP_FACTOR : 1 / ZOOM_STEP_FACTOR;
+ zoomAtPoint(referencePoint, zoomFactor);
});
// 榧犳爣鎷栨嫿绉诲姩
@@ -168,12 +233,6 @@
visualizationPanel.repaint();
}
}
-
- public void mouseMoved(MouseEvent e) {
- // 鏇存柊榧犳爣浣嶇疆鐢ㄤ簬鏄剧ず鍧愭爣
- mousePoint = e.getPoint();
- visualizationPanel.repaint();
- }
});
}
@@ -197,34 +256,71 @@
/**
* 鍩轰簬榧犳爣浣嶇疆鐨勭缉鏀�
*/
- private void zoomAtPoint(double zoomFactor) {
- if (mousePoint == null) return;
-
- // 璁$畻榧犳爣浣嶇疆鍦ㄤ笘鐣屽潗鏍囩郴涓殑鍧愭爣
- double worldX = (mousePoint.x - visualizationPanel.getWidth()/2) / scale - translateX;
- double worldY = (mousePoint.y - visualizationPanel.getHeight()/2) / scale - translateY;
+ private void zoomAtPoint(Point referencePoint, double zoomFactor) {
+ if (visualizationPanel == null) {
+ return;
+ }
+ if (referencePoint == null) {
+ referencePoint = new Point(visualizationPanel.getWidth() / 2, visualizationPanel.getHeight() / 2);
+ }
- scale *= zoomFactor;
- scale = Math.max(0.05, Math.min(scale, 50.0)); // 闄愬埗缂╂斁鑼冨洿锛屽厑璁告渶澶氱缉灏忚嚦鍘熷鐨�1/20
-
- // 璁$畻缂╂斁鍚庡悓涓�榧犳爣浣嶇疆鍦ㄤ笘鐣屽潗鏍囩郴涓殑鏂板潗鏍�
- double newWorldX = (mousePoint.x - visualizationPanel.getWidth()/2) / scale - translateX;
- double newWorldY = (mousePoint.y - visualizationPanel.getHeight()/2) / scale - translateY;
-
- // 璋冩暣骞崇Щ閲忥紝浣块紶鏍囨寚鍚戠殑涓栫晫鍧愭爣淇濇寔涓嶅彉
+ double panelCenterX = visualizationPanel.getWidth() / 2.0;
+ double panelCenterY = visualizationPanel.getHeight() / 2.0;
+
+ double worldX = (referencePoint.x - panelCenterX) / scale - translateX;
+ double worldY = (referencePoint.y - panelCenterY) / scale - translateY;
+
+ scale *= zoomFactor;
+ scale = Math.max(MIN_SCALE, Math.min(scale, MAX_SCALE)); // 闄愬埗缂╂斁鑼冨洿锛屽厑璁告渶澶氱缉灏忚嚦鍘熷鐨�1/20
+
+ double newWorldX = (referencePoint.x - panelCenterX) / scale - translateX;
+ double newWorldY = (referencePoint.y - panelCenterY) / scale - translateY;
+
translateX += (newWorldX - worldX);
translateY += (newWorldY - worldY);
-
+
+ // 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ saveScaleToProperties();
visualizationPanel.repaint();
}
+
+ public void zoomInFromCenter() {
+ zoomAtPoint(null, ZOOM_STEP_FACTOR);
+ }
+
+ public void zoomOutFromCenter() {
+ zoomAtPoint(null, 1 / ZOOM_STEP_FACTOR);
+ }
+
+ public boolean canZoomIn() {
+ return scale < MAX_SCALE - SCALE_EPSILON;
+ }
+
+ public boolean canZoomOut() {
+ return scale > MIN_SCALE + SCALE_EPSILON;
+ }
+
+ public double getScale() {
+ return scale;
+ }
+
+ public double getMaxScale() {
+ return MAX_SCALE;
+ }
+
+ public double getMinScale() {
+ return MIN_SCALE;
+ }
/**
* 閲嶇疆瑙嗗浘
*/
public void resetView() {
- scale = 1.0;
+ scale = DEFAULT_SCALE;
translateX = 0.0;
translateY = 0.0;
+ // 淇濆瓨缂╂斁姣斾緥鍒伴厤缃枃浠�
+ saveScaleToProperties();
visualizationPanel.repaint();
}
@@ -451,7 +547,8 @@
if (device == null) {
return;
}
- if (!isHighPrecisionFix(device.getPositioningStatus())) {
+ // 浣跨敤鏇村鏉剧殑瀹氫綅鐘舵�佸垽鏂紝鍏佽鐘舵��1鍜�4鏄剧ず鎷栧熬
+ if (!isValidFixForTrail(device.getPositioningStatus())) {
return;
}
@@ -473,6 +570,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()) {
@@ -1202,6 +1349,32 @@
return false;
}
}
+
+ /**
+ * 鍒ゆ柇瀹氫綅鐘舵�佹槸鍚︽湁鏁堬紝鍙敤浜庢樉绀烘嫋灏�
+ * 鎺ュ彈鐘舵��1锛堝崟鐐瑰畾浣嶏級銆�2锛堢爜宸垎锛夈��3锛堟棤鏁圥PS锛夈��4锛堝浐瀹氳В锛夈��5锛堟诞鐐硅В锛�
+ */
+ private boolean isValidFixForTrail(String fixQuality) {
+ if (fixQuality == null) {
+ return false;
+ }
+ String trimmed = fixQuality.trim();
+ if (trimmed.isEmpty()) {
+ return false;
+ }
+ // 鎺ュ彈鐘舵��1,2,3,4,5锛堝彧瑕佷笉鏄�0鎴栨棤鏁堢姸鎬侊級
+ if ("1".equals(trimmed) || "2".equals(trimmed) || "3".equals(trimmed) ||
+ "4".equals(trimmed) || "5".equals(trimmed)) {
+ return true;
+ }
+ try {
+ double value = Double.parseDouble(trimmed);
+ // 鎺ュ彈1.0, 2.0, 3.0, 4.0, 5.0锛堝彧瑕佷笉鏄�0锛�
+ return value >= 1.0 && value <= 5.0;
+ } catch (NumberFormatException ex) {
+ return false;
+ }
+ }
private boolean isPointInsideActiveBoundary(Point2D.Double point) {
if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) {
@@ -1260,30 +1433,34 @@
private void drawViewInfo(Graphics2D g2d) {
g2d.setColor(new Color(80, 80, 80));
g2d.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 11));
-
- // 鍙樉绀虹缉鏀炬瘮渚嬶紝鍘绘帀骞崇Щ淇℃伅
- String info = String.format("缂╂斁: %.2fx", scale);
- g2d.drawString(info, 15, visualizationPanel.getHeight() - 15);
-
- if (mousePoint != null) {
- // 璁$畻榧犳爣浣嶇疆鍦ㄤ笘鐣屽潗鏍囩郴涓殑鍧愭爣
- double worldX = (mousePoint.x - visualizationPanel.getWidth()/2) / scale - translateX;
- double worldY = (mousePoint.y - visualizationPanel.getHeight()/2) / scale - translateY;
-
- String mouseCoord = String.format("鍧愭爣: (%.1f, %.1f)m", worldX, worldY);
- g2d.drawString(mouseCoord, visualizationPanel.getWidth() - 150, visualizationPanel.getHeight() - 15);
+
+ // 鍦ㄥ湴鍥鹃《閮ㄥ乏渚ф樉绀洪仴鎺ф憞鏉嗗搴旈�熷害锛堣嫢闈為浂锛�
+ try {
+ int forward = Control03.getCurrentForwardSpeed();
+ int steer = Control03.getCurrentSteeringSpeed();
+ if (forward != 0 || steer != 0) {
+ String speedInfo = String.format("琛岃繘:%d 杞悜:%d", forward, steer);
+ // 鑳屾櫙鍗婇�忔槑鐭╁舰澧炲己鍙鎬�
+ FontMetrics fm = g2d.getFontMetrics();
+ int padding = 6;
+ int w = fm.stringWidth(speedInfo) + padding * 2;
+ int h = fm.getHeight() + padding;
+ int x = 12;
+ int y = 12;
+ Color bg = new Color(255, 255, 255, 180);
+ g2d.setColor(bg);
+ g2d.fillRoundRect(x, y, w, h, 8, 8);
+ g2d.setColor(new Color(120, 120, 120));
+ g2d.drawString(speedInfo, x + padding, y + fm.getAscent() + (padding/2));
+ }
+ } catch (Throwable t) {
+ // 涓嶅簲闃诲娓叉煋锛岄潤榛樺鐞嗕换浣曞紓甯�
}
-
- // 鍘绘帀鎿嶄綔鎻愮ず锛�"婊氳疆缂╂斁 | 鎷栨嫿绉诲姩 | 鍙抽敭閲嶇疆"
- // String tips = "婊氳疆缂╂斁 | 鎷栨嫿绉诲姩 | 鍙抽敭閲嶇疆";
- // g2d.drawString(tips, visualizationPanel.getWidth() - 200, 30);
- }
-
- /**
- * 鑾峰彇褰撳墠缂╂斁姣斾緥
- */
- public double getScale() {
- return scale;
+
+ // 淇濈暀搴曢儴鐨勭缉鏀炬瘮渚嬩俊鎭�
+ String info = String.format("缂╂斁: %.2fx", scale);
+ g2d.setColor(new Color(80, 80, 80));
+ g2d.drawString(info, 15, visualizationPanel.getHeight() - 15);
}
/**
@@ -1304,7 +1481,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();
@@ -2046,4 +2231,20 @@
mowerInfoManager.dispose();
}
+ /**
+ * 鑾峰彇褰撳墠杈圭晫鐐瑰垪琛�
+ * @return 褰撳墠杈圭晫鐐瑰垪琛紝濡傛灉娌℃湁杈圭晫鍒欒繑鍥瀗ull
+ */
+ public List<Point2D.Double> getCurrentBoundary() {
+ return currentBoundary;
+ }
+
+ /**
+ * 鑾峰彇鍓茶崏鏈哄疄渚�
+ * @return 鍓茶崏鏈哄疄渚�
+ */
+ public Gecaoji getMower() {
+ return mower;
+ }
+
}
\ No newline at end of file
--
Gitblit v1.10.0