From 32524195d474b74e48916867b2a6c2f022a40d98 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 09 十二月 2025 19:36:32 +0800
Subject: [PATCH] 20251209

---
 src/zhuye/MapRenderer.java |  126 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 118 insertions(+), 8 deletions(-)

diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 5f5dd06..4562a15 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -50,6 +50,7 @@
     private static final double CIRCLE_SAMPLE_SIZE = 0.54d;
     private static final double BOUNDARY_POINT_MERGE_THRESHOLD = 0.05;
     private static final double BOUNDARY_CONTAINS_TOLERANCE = 0.05;
+    private static final double PREVIEW_BOUNDARY_MARKER_SCALE = 0.25d;
     
     // 缁勪欢寮曠敤
     private JPanel visualizationPanel;
@@ -64,6 +65,8 @@
     private String currentObstacleLandNumber;
     private String boundaryName;
     private boolean boundaryPointsVisible;
+    private double boundaryPointSizeScale = 1.0d;
+    private boolean previewSizingEnabled;
     private String currentBoundaryLandNumber;
     private boolean dragInProgress;
     private final Gecaoji mower;
@@ -74,6 +77,7 @@
     private final List<Point2D.Double> realtimeMowingTrack = new ArrayList<>();
     private final Deque<tuowei.TrailSample> idleMowerTrail = new ArrayDeque<>();
     private final List<Point2D.Double> handheldBoundaryPreview = new ArrayList<>();
+    private double boundaryPreviewMarkerScale = 1.0d;
     private boolean realtimeTrackRecording;
     private String realtimeTrackLandNumber;
     private double mowerEffectiveWidthMeters;
@@ -264,19 +268,21 @@
             drawCircleCaptureOverlay(g2d, circleCaptureOverlay, scale);
         }
 
-        adddikuaiyulan.drawPreview(g2d, handheldBoundaryPreview, scale, handheldBoundaryPreviewActive);
+    adddikuaiyulan.drawPreview(g2d, handheldBoundaryPreview, scale, handheldBoundaryPreviewActive, boundaryPreviewMarkerScale);
 
         if (hasPlannedPath) {
             drawCurrentPlannedPath(g2d);
         }
 
         if (boundaryPointsVisible && hasBoundary) {
+            double markerScale = boundaryPointSizeScale * (previewSizingEnabled ? PREVIEW_BOUNDARY_MARKER_SCALE : 1.0d);
             pointandnumber.drawBoundaryPoints(
                 g2d,
                 currentBoundary,
                 scale,
                 BOUNDARY_POINT_MERGE_THRESHOLD,
-                BOUNDARY_POINT_COLOR
+                BOUNDARY_POINT_COLOR,
+                markerScale
             );
         }
 
@@ -648,6 +654,10 @@
         visualizationPanel.repaint();
     }
 
+    public void clearIdleTrail() {
+        clearIdleMowerTrail();
+    }
+
     public void setIdleTrailDurationSeconds(int seconds) {
         int sanitized = seconds;
         if (sanitized < 5 || sanitized > 600) {
@@ -865,7 +875,8 @@
     }
 
     private void drawCurrentPlannedPath(Graphics2D g2d) {
-        lujingdraw.drawPlannedPath(g2d, currentPlannedPath, scale);
+        double arrowScale = previewSizingEnabled ? 0.5d : 1.0d;
+        lujingdraw.drawPlannedPath(g2d, currentPlannedPath, scale, arrowScale);
     }
 
     private void drawCircleSampleMarkers(Graphics2D g2d, List<double[]> markers, double scale) {
@@ -1054,7 +1065,11 @@
 
     private double computeSelectionThresholdPixels() {
         double scaleFactor = Math.max(0.5, scale);
-        double markerDiameterWorld = Math.max(1.0, (10.0 / scaleFactor) * 0.2);
+        double diameterScale = boundaryPointSizeScale * (previewSizingEnabled ? PREVIEW_BOUNDARY_MARKER_SCALE : 1.0d);
+        if (!Double.isFinite(diameterScale) || diameterScale <= 0.0d) {
+            diameterScale = 1.0d;
+        }
+        double markerDiameterWorld = Math.max(1.0, (10.0 / scaleFactor) * 0.2 * diameterScale);
         double markerDiameterPixels = markerDiameterWorld * scale;
         return Math.max(8.0, markerDiameterPixels * 1.5);
     }
@@ -1830,6 +1845,65 @@
         visualizationPanel.repaint();
     }
 
+    public void setBoundaryPointSizeScale(double sizeScale) {
+        double normalized = (Double.isFinite(sizeScale) && sizeScale > 0.0d) ? sizeScale : 1.0d;
+        if (Math.abs(boundaryPointSizeScale - normalized) < 1e-6) {
+            return;
+        }
+        boundaryPointSizeScale = normalized;
+        if (visualizationPanel == null) {
+            return;
+        }
+        if (SwingUtilities.isEventDispatchThread()) {
+            visualizationPanel.repaint();
+        } else {
+            SwingUtilities.invokeLater(visualizationPanel::repaint);
+        }
+    }
+
+    public void setPathPreviewSizingEnabled(boolean enabled) {
+        previewSizingEnabled = enabled;
+        if (visualizationPanel == null) {
+            return;
+        }
+        if (SwingUtilities.isEventDispatchThread()) {
+            visualizationPanel.repaint();
+        } else {
+            SwingUtilities.invokeLater(visualizationPanel::repaint);
+        }
+    }
+
+    public void setBoundaryPreviewMarkerScale(double markerScale) {
+        double normalized = Double.isFinite(markerScale) && markerScale > 0.0d ? markerScale : 1.0d;
+        if (Math.abs(boundaryPreviewMarkerScale - normalized) < 1e-6) {
+            return;
+        }
+        boundaryPreviewMarkerScale = normalized;
+        if (visualizationPanel == null) {
+            return;
+        }
+        if (SwingUtilities.isEventDispatchThread()) {
+            visualizationPanel.repaint();
+        } else {
+            SwingUtilities.invokeLater(visualizationPanel::repaint);
+        }
+    }
+
+    public boolean setHandheldMowerIconActive(boolean handheldActive) {
+        if (mower == null) {
+            return false;
+        }
+        boolean changed = mower.useHandheldIcon(handheldActive);
+        if (changed && visualizationPanel != null) {
+            if (SwingUtilities.isEventDispatchThread()) {
+                visualizationPanel.repaint();
+            } else {
+                SwingUtilities.invokeLater(visualizationPanel::repaint);
+            }
+        }
+        return changed;
+    }
+
     public void beginHandheldBoundaryPreview() {
         handheldBoundaryPreviewActive = true;
         handheldBoundaryPreview.clear();
@@ -1859,6 +1933,7 @@
     public void clearHandheldBoundaryPreview() {
         handheldBoundaryPreviewActive = false;
         handheldBoundaryPreview.clear();
+        boundaryPreviewMarkerScale = 1.0d;
         visualizationPanel.repaint();
     }
 
@@ -1914,8 +1989,10 @@
             return;
         }
 
-        double width = Math.max(bounds.width, 1);
-        double height = Math.max(bounds.height, 1);
+        Rectangle2D.Double targetBounds = includeMowerInBounds(bounds);
+
+        double width = Math.max(targetBounds.width, 1);
+        double height = Math.max(targetBounds.height, 1);
 
         double targetWidth = width * 1.2;
         double targetHeight = height * 1.2;
@@ -1927,8 +2004,41 @@
         newScale = Math.max(0.05, Math.min(newScale, 50.0));
 
         this.scale = newScale;
-        this.translateX = -bounds.getCenterX();
-        this.translateY = -bounds.getCenterY();
+        this.translateX = -targetBounds.getCenterX();
+        this.translateY = -targetBounds.getCenterY();
+    }
+
+    // Keep the mower marker inside the viewport whenever the camera refits to scene bounds.
+    private Rectangle2D.Double includeMowerInBounds(Rectangle2D.Double bounds) {
+        Rectangle2D.Double expanded = new Rectangle2D.Double(
+            bounds.x,
+            bounds.y,
+            Math.max(0.0, bounds.width),
+            Math.max(0.0, bounds.height)
+        );
+
+        if (mower == null || !mower.hasValidPosition()) {
+            return expanded;
+        }
+
+        Point2D.Double mowerPosition = mower.getPosition();
+        if (mowerPosition == null
+            || !Double.isFinite(mowerPosition.x)
+            || !Double.isFinite(mowerPosition.y)) {
+            return expanded;
+        }
+
+        double minX = Math.min(expanded.x, mowerPosition.x);
+        double minY = Math.min(expanded.y, mowerPosition.y);
+        double maxX = Math.max(expanded.x + expanded.width, mowerPosition.x);
+        double maxY = Math.max(expanded.y + expanded.height, mowerPosition.y);
+
+        expanded.x = minX;
+        expanded.y = minY;
+        expanded.width = Math.max(0.0, maxX - minX);
+        expanded.height = Math.max(0.0, maxY - minY);
+
+        return expanded;
     }
 
     public void dispose() {

--
Gitblit v1.10.0