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