From 3ad76f98fa8b4a9d3d95207cfb4ae4706087c964 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期四, 04 十二月 2025 19:14:15 +0800
Subject: [PATCH] 新增20251204
---
src/zhuye/MapRenderer.java | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 162 insertions(+), 4 deletions(-)
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 3352dc2..b5665ee 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -52,11 +52,13 @@
private static final Color HANDHELD_BOUNDARY_BORDER = new Color(51, 102, 204, 220);
private static final Color HANDHELD_BOUNDARY_POINT = new Color(51, 102, 204);
private static final Color HANDHELD_BOUNDARY_LABEL = new Color(22, 62, 138);
+ private static final double BOUNDARY_CONTAINS_TOLERANCE = 0.05;
// 缁勪欢寮曠敤
private JPanel visualizationPanel;
private List<Point2D.Double> currentBoundary;
private Rectangle2D.Double boundaryBounds;
+ private Path2D.Double currentBoundaryPath;
private List<Point2D.Double> currentPlannedPath;
private Rectangle2D.Double plannedPathBounds;
private List<Obstacledge.Obstacle> currentObstacles;
@@ -94,6 +96,7 @@
private long lastTrackPersistTimeMillis;
private boolean trackDirty;
private boolean handheldBoundaryPreviewActive;
+ private boolean pendingTrackBreak = true;
private static final double TRACK_SAMPLE_MIN_DISTANCE_METERS = 0.1d;
private static final long TRACK_PERSIST_INTERVAL_MS = 5_000L;
@@ -432,15 +435,39 @@
}
private void captureRealtimeTrackPoint() {
+ if (!realtimeTrackRecording) {
+ return;
+ }
if (realtimeTrackLandNumber == null || visualizationPanel == null) {
+ pendingTrackBreak = true;
+ return;
+ }
+ Device device = Device.getGecaoji();
+ if (device == null) {
+ pendingTrackBreak = true;
+ return;
+ }
+
+ String fixQuality = device.getPositioningStatus();
+ if (!isHighPrecisionFix(fixQuality)) {
+ pendingTrackBreak = true;
return;
}
Point2D.Double position = mower.getPosition();
if (position == null || !Double.isFinite(position.x) || !Double.isFinite(position.y)) {
+ pendingTrackBreak = true;
+ return;
+ }
+
+ if (!isPointInsideActiveBoundary(position)) {
+ pendingTrackBreak = true;
return;
}
Point2D.Double lastPoint = realtimeMowingTrack.isEmpty() ? null : realtimeMowingTrack.get(realtimeMowingTrack.size() - 1);
+ if (pendingTrackBreak) {
+ lastPoint = null;
+ }
double distance = 0.0;
if (lastPoint != null) {
double dx = position.x - lastPoint.x;
@@ -459,6 +486,7 @@
updateCompletionMetrics();
trackDirty = true;
maybePersistRealtimeTrack(false);
+ pendingTrackBreak = false;
}
private void updateCompletionMetrics() {
@@ -575,16 +603,19 @@
realtimeTrackLandNumber = normalizedLand;
realtimeTrackRecording = true;
+ pendingTrackBreak = true;
captureRealtimeTrackPoint();
}
public void pauseRealtimeTrackRecording() {
realtimeTrackRecording = false;
+ pendingTrackBreak = true;
maybePersistRealtimeTrack(true);
}
public void stopRealtimeTrackRecording() {
realtimeTrackRecording = false;
+ pendingTrackBreak = true;
maybePersistRealtimeTrack(true);
}
@@ -602,15 +633,22 @@
completedMowingAreaSqMeters = 0.0;
mowingCompletionRatio = 0.0;
trackDirty = true;
+ pendingTrackBreak = true;
maybePersistRealtimeTrack(true);
visualizationPanel.repaint();
}
public double getMowingCompletionRatio() {
+ if (!isMowerInsideSelectedBoundary()) {
+ return 0.0;
+ }
return mowingCompletionRatio;
}
public double getCompletedMowingAreaSqMeters() {
+ if (!isMowerInsideSelectedBoundary()) {
+ return 0.0;
+ }
return completedMowingAreaSqMeters;
}
@@ -622,6 +660,14 @@
return trackLengthMeters;
}
+ private boolean isMowerInsideSelectedBoundary() {
+ Point2D.Double position = mower.getPosition();
+ if (position == null) {
+ return false;
+ }
+ return isPointInsideActiveBoundary(position);
+ }
+
public void flushRealtimeTrack() {
maybePersistRealtimeTrack(true);
}
@@ -635,6 +681,7 @@
mowingCompletionRatio = 0.0;
trackDirty = false;
lastTrackPersistTimeMillis = 0L;
+ pendingTrackBreak = true;
String trimmed = normalizeValue(trackData);
if (trimmed == null || trimmed.isEmpty()) {
@@ -1071,7 +1118,7 @@
mowerNumberValueLabel.setText(formatDeviceValue(device.getMowerNumber()));
realtimeXValueLabel.setText(formatDeviceValue(device.getRealtimeX()));
realtimeYValueLabel.setText(formatDeviceValue(device.getRealtimeY()));
- positioningStatusValueLabel.setText(formatDeviceValue(device.getPositioningStatus()));
+ positioningStatusValueLabel.setText(formatFixQualityValue(device.getPositioningStatus()));
satelliteCountValueLabel.setText(formatDeviceValue(device.getSatelliteCount()));
realtimeSpeedValueLabel.setText(formatDeviceValue(device.getRealtimeSpeed()));
headingValueLabel.setText(formatDeviceValue(device.getHeading()));
@@ -1082,7 +1129,7 @@
if (mowerNumberValueLabel != null) mowerNumberValueLabel.setText(value);
if (realtimeXValueLabel != null) realtimeXValueLabel.setText(value);
if (realtimeYValueLabel != null) realtimeYValueLabel.setText(value);
- if (positioningStatusValueLabel != null) positioningStatusValueLabel.setText(value);
+ if (positioningStatusValueLabel != null) positioningStatusValueLabel.setText(value);
if (satelliteCountValueLabel != null) satelliteCountValueLabel.setText(value);
if (realtimeSpeedValueLabel != null) realtimeSpeedValueLabel.setText(value);
if (headingValueLabel != null) headingValueLabel.setText(value);
@@ -1105,6 +1152,37 @@
return sanitized == null ? "--" : sanitized;
}
+ private String formatFixQualityValue(String value) {
+ String sanitized = sanitizeDeviceValue(value);
+ if (sanitized == null) {
+ return "--";
+ }
+ switch (sanitized) {
+ case "0":
+ return "鏈畾浣�";
+ case "1":
+ return "鍗曠偣瀹氫綅";
+ case "2":
+ return "鐮佸樊鍒�";
+ case "3":
+ return "鏃犳晥PPS";
+ case "4":
+ return "鍥哄畾瑙�";
+ case "5":
+ return "娴偣瑙�";
+ case "6":
+ return "姝e湪浼扮畻";
+ case "7":
+ return "浜哄伐杈撳叆鍥哄畾鍊�";
+ case "8":
+ return "妯℃嫙妯″紡";
+ case "9":
+ return "WAAS宸垎";
+ default:
+ return sanitized;
+ }
+ }
+
private String formatTimestamp(String value) {
String sanitized = sanitizeDeviceValue(value);
if (sanitized == null) {
@@ -1207,6 +1285,7 @@
if (updated.size() < 2) {
currentBoundary = null;
+ currentBoundaryPath = null;
boundaryBounds = null;
boundaryPointsVisible = false;
Dikuaiguanli.updateBoundaryPointVisibility(currentBoundaryLandNumber, false);
@@ -1214,10 +1293,12 @@
adjustViewAfterBoundaryReset();
} else {
currentBoundary = updated;
+ rebuildBoundaryPath();
boundaryBounds = computeBounds(updated);
Dikuaiguanli.updateBoundaryPointVisibility(currentBoundaryLandNumber, boundaryPointsVisible);
visualizationPanel.repaint();
}
+ pendingTrackBreak = true;
}
private boolean persistBoundaryChanges(List<Point2D.Double> updatedBoundary) {
@@ -1279,6 +1360,79 @@
return Math.hypot(dx, dy) <= BOUNDARY_POINT_MERGE_THRESHOLD;
}
+ private boolean isHighPrecisionFix(String fixQuality) {
+ if (fixQuality == null) {
+ return false;
+ }
+ String trimmed = fixQuality.trim();
+ if (trimmed.isEmpty()) {
+ return false;
+ }
+ if ("4".equals(trimmed)) {
+ return true;
+ }
+ try {
+ double value = Double.parseDouble(trimmed);
+ return 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)) {
+ return false;
+ }
+ if (realtimeTrackLandNumber == null) {
+ return false;
+ }
+ if (currentBoundaryLandNumber != null && !currentBoundaryLandNumber.equals(realtimeTrackLandNumber)) {
+ return false;
+ }
+
+ Path2D.Double path = currentBoundaryPath;
+ if (path == null) {
+ path = buildBoundaryPath(currentBoundary);
+ currentBoundaryPath = path;
+ }
+ if (path == null) {
+ return false;
+ }
+ if (path.contains(point.x, point.y)) {
+ return true;
+ }
+ double size = BOUNDARY_CONTAINS_TOLERANCE * 2.0;
+ return path.intersects(point.x - BOUNDARY_CONTAINS_TOLERANCE, point.y - BOUNDARY_CONTAINS_TOLERANCE, size, size);
+ }
+
+ private void rebuildBoundaryPath() {
+ currentBoundaryPath = buildBoundaryPath(currentBoundary);
+ }
+
+ private Path2D.Double buildBoundaryPath(List<Point2D.Double> boundary) {
+ if (boundary == null || boundary.size() < 3) {
+ return null;
+ }
+ Path2D.Double path = new Path2D.Double();
+ boolean started = false;
+ for (Point2D.Double point : boundary) {
+ if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) {
+ continue;
+ }
+ if (!started) {
+ path.moveTo(point.x, point.y);
+ started = true;
+ } else {
+ path.lineTo(point.x, point.y);
+ }
+ }
+ if (!started) {
+ return null;
+ }
+ path.closePath();
+ return path;
+ }
+
/**
* 缁樺埗瑙嗗浘淇℃伅
@@ -1360,8 +1514,10 @@
return;
}
- currentBoundary = parsed;
- boundaryBounds = computeBounds(parsed);
+ currentBoundary = parsed;
+ rebuildBoundaryPath();
+ pendingTrackBreak = true;
+ boundaryBounds = computeBounds(parsed);
Rectangle2D.Double bounds = boundaryBounds;
SwingUtilities.invokeLater(() -> {
@@ -1372,10 +1528,12 @@
private void clearBoundaryData() {
currentBoundary = null;
+ currentBoundaryPath = null;
boundaryBounds = null;
boundaryName = null;
boundaryPointsVisible = false;
currentBoundaryLandNumber = null;
+ pendingTrackBreak = true;
}
public void setCurrentObstacles(String obstaclesData, String landNumber) {
--
Gitblit v1.10.0