From ed6936545d20cc490145d2936cee4387be2afd53 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期一, 22 十二月 2025 19:04:34 +0800
Subject: [PATCH] 优化了导航预览模式
---
src/gecaoji/Gecaoji.java | 142 ++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 128 insertions(+), 14 deletions(-)
diff --git a/src/gecaoji/Gecaoji.java b/src/gecaoji/Gecaoji.java
index b5e142e..d47353c 100644
--- a/src/gecaoji/Gecaoji.java
+++ b/src/gecaoji/Gecaoji.java
@@ -12,33 +12,48 @@
/** Mower rendering helper. */
public class Gecaoji {
private static final double ICON_PIXEL_SIZE = 48.0;
+ private static final double ICON_SCALE_FACTOR = 0.8;
private static final double MIN_SCALE = 1e-6;
private static final Color FALLBACK_FILL = new Color(0, 150, 0);
+ private static final String DEFAULT_ICON_PATH = "image/gecaoji.png";
+ private static final String HANDHELD_ICON_PATH = "image/URT.png";
- private final Image mowerIcon;
+ private final Image defaultIcon;
+ private final Image handheldIcon;
+ private Image activeIcon;
+ private boolean handheldIconActive;
private final Ellipse2D.Double fallbackShape = new Ellipse2D.Double();
private Point2D.Double position = new Point2D.Double();
private boolean positionValid;
+ private double headingDegrees;
public Gecaoji() {
- mowerIcon = loadIcon();
+ defaultIcon = loadIcon(DEFAULT_ICON_PATH);
+ handheldIcon = loadIcon(HANDHELD_ICON_PATH);
+ activeIcon = defaultIcon != null ? defaultIcon : handheldIcon;
+ handheldIconActive = false;
refreshFromDevice();
}
- private Image loadIcon() {
+ private Image loadIcon(String path) {
try {
- ImageIcon icon = new ImageIcon("image/mow.png");
+ ImageIcon icon = new ImageIcon(path);
if (icon.getIconWidth() <= 0 || icon.getIconHeight() <= 0) {
return null;
}
return icon.getImage();
} catch (Exception ex) {
- System.err.println("Unable to load mower icon: " + ex.getMessage());
+ System.err.println("Unable to load mower icon from " + path + ": " + ex.getMessage());
return null;
}
}
public void refreshFromDevice() {
+ // 妫�鏌ユ槸鍚︽鍦ㄥ鑸瑙堟ā寮忥紝濡傛灉鏄垯涓嶆洿鏂颁綅缃�
+ if (isNavigating()) {
+ return;
+ }
+
Device device = Device.getGecaoji();
if (device == null) {
positionValid = false;
@@ -47,8 +62,9 @@
double x = parseCoordinate(device.getRealtimeX());
double y = parseCoordinate(device.getRealtimeY());
+ double heading = parseHeading(device.getHeading());
if (Double.isNaN(x) || Double.isNaN(y)) {
- positionValid = false;
+ // Keep showing the last known mower position when temporary sensor glitches occur.
return;
}
@@ -56,6 +72,23 @@
position.x = x;
position.y = y;
positionValid = true;
+ headingDegrees = heading;
+ }
+
+ /**
+ * 妫�鏌ユ槸鍚︽鍦ㄥ鑸瑙堟ā寮�
+ * @return 濡傛灉姝e湪瀵艰埅棰勮杩斿洖true锛屽惁鍒欒繑鍥瀎alse
+ */
+ private boolean isNavigating() {
+ try {
+ dikuai.daohangyulan nav = dikuai.daohangyulan.getInstance();
+ if (nav != null) {
+ return nav.isNavigating();
+ }
+ } catch (Exception e) {
+ // 濡傛灉鑾峰彇瀵艰埅瀹炰緥澶辫触锛岃繑鍥瀎alse锛堜笉褰卞搷涓昏鍔熻兘锛�
+ }
+ return false;
}
private void ensurePosition() {
@@ -79,32 +112,57 @@
}
}
+ private double parseHeading(String value) {
+ if (value == null) {
+ return 0.0;
+ }
+ String trimmed = value.trim();
+ if (trimmed.isEmpty() || "-1".equals(trimmed)) {
+ return 0.0;
+ }
+ try {
+ double parsed = Double.parseDouble(trimmed);
+ if (!Double.isFinite(parsed)) {
+ return 0.0;
+ }
+ double normalized = parsed % 360.0;
+ return normalized < 0 ? normalized + 360.0 : normalized;
+ } catch (NumberFormatException ex) {
+ return 0.0;
+ }
+ }
+
public void draw(Graphics2D g2d, double scale) {
if (!positionValid) {
return;
}
- double worldSize = ICON_PIXEL_SIZE / Math.max(scale, MIN_SCALE);
- if (mowerIcon != null && mowerIcon.getWidth(null) > 0 && mowerIcon.getHeight(null) > 0) {
- drawIcon(g2d, worldSize);
+ double worldSize = (ICON_PIXEL_SIZE * ICON_SCALE_FACTOR) / Math.max(scale, MIN_SCALE);
+ Image icon = activeIcon;
+ if (icon != null && icon.getWidth(null) > 0 && icon.getHeight(null) > 0) {
+ drawIcon(g2d, worldSize, icon);
} else {
drawFallback(g2d, worldSize);
}
}
- private void drawIcon(Graphics2D g2d, double worldSize) {
- double iconWidth = mowerIcon.getWidth(null);
- double iconHeight = mowerIcon.getHeight(null);
+ private void drawIcon(Graphics2D g2d, double worldSize, Image icon) {
+ double iconWidth = icon.getWidth(null);
+ double iconHeight = icon.getHeight(null);
double maxSide = Math.max(iconWidth, iconHeight);
double scaleFactor = worldSize / Math.max(maxSide, MIN_SCALE);
+ double rotationRadians = Math.toRadians(-headingDegrees);
AffineTransform original = g2d.getTransform();
AffineTransform transformed = new AffineTransform(original);
transformed.translate(position.x, position.y);
+ if (rotationRadians != 0.0) {
+ transformed.rotate(rotationRadians);
+ }
transformed.scale(scaleFactor, scaleFactor);
transformed.translate(-iconWidth / 2.0, -iconHeight / 2.0);
g2d.setTransform(transformed);
- g2d.drawImage(mowerIcon, 0, 0, null);
+ g2d.drawImage(icon, 0, 0, null);
g2d.setTransform(original);
}
@@ -118,6 +176,15 @@
g2d.fill(fallbackShape);
g2d.setColor(Color.WHITE);
g2d.draw(fallbackShape);
+ double rotationRadians = Math.toRadians(-headingDegrees);
+ double lineLength = radius;
+ double dx = lineLength * Math.sin(rotationRadians);
+ double dy = lineLength * Math.cos(rotationRadians);
+ g2d.drawLine(
+ (int) Math.round(position.x),
+ (int) Math.round(position.y),
+ (int) Math.round(position.x + dx),
+ (int) Math.round(position.y + dy));
g2d.setColor(original);
}
@@ -133,11 +200,58 @@
return new Point2D.Double(position.x, position.y);
}
+ /**
+ * 璁剧疆鍓茶崏鏈轰綅缃紙鐢ㄤ簬瀵艰埅棰勮绛夊満鏅級
+ * @param x X鍧愭爣
+ * @param y Y鍧愭爣
+ */
+ public void setPosition(double x, double y) {
+ ensurePosition();
+ position.x = x;
+ position.y = y;
+ positionValid = true;
+ }
+
+ /**
+ * 璁剧疆鍓茶崏鏈烘柟鍚戯紙鐢ㄤ簬瀵艰埅棰勮绛夊満鏅級
+ * @param headingDegrees 鏂瑰悜瑙掑害锛堝害锛�0-360锛�
+ */
+ public void setHeading(double headingDegrees) {
+ double normalized = headingDegrees % 360.0;
+ if (normalized < 0) {
+ normalized += 360.0;
+ }
+ this.headingDegrees = normalized;
+ }
+
+ /**
+ * 鑾峰彇鍓茶崏鏈烘柟鍚�
+ * @return 鏂瑰悜瑙掑害锛堝害锛�0-360锛�
+ */
+ public double getHeading() {
+ return headingDegrees;
+ }
+
public double getWorldRadius(double scale) {
if (!positionValid) {
return Double.NaN;
}
- double worldSize = ICON_PIXEL_SIZE / Math.max(scale, MIN_SCALE);
+ double worldSize = (ICON_PIXEL_SIZE * ICON_SCALE_FACTOR) / Math.max(scale, MIN_SCALE);
return worldSize / 2.0;
}
+
+ public boolean useHandheldIcon(boolean handheldMode) {
+ if (handheldIconActive == handheldMode) {
+ return false;
+ }
+ handheldIconActive = handheldMode;
+ Image next = handheldMode
+ ? (handheldIcon != null ? handheldIcon : defaultIcon)
+ : defaultIcon;
+ if (next == null) {
+ next = handheldIcon;
+ }
+ activeIcon = next;
+ return true;
+ }
}
--
Gitblit v1.10.0