From 6799351be12deb2f713f2c0a2b4c467a6d1098c3 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 02 十二月 2025 19:51:00 +0800
Subject: [PATCH] 2025122
---
src/zhuye/MapRenderer.java | 335 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 322 insertions(+), 13 deletions(-)
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index aebc291..9cb5475 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -3,21 +3,27 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
+import java.awt.FontMetrics;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import gecaoji.Device;
import gecaoji.Gecaoji;
import dikuai.Dikuaiguanli;
import dikuai.Dikuai;
import zhangaiwu.Obstacledraw;
import zhangaiwu.Obstacledge;
+import zhangaiwu.yulanzhangaiwu;
/**
* 鍦板浘娓叉煋鍣� - 璐熻矗鍧愭爣绯荤粯鍒躲�佽鍥惧彉鎹㈢瓑鍔熻兘
@@ -37,6 +43,8 @@
private static final Color GRASS_BORDER_COLOR = new Color(60, 179, 113);
private static final Color BOUNDARY_POINT_COLOR = new Color(128, 0, 128);
private static final Color BOUNDARY_LABEL_COLOR = Color.BLACK;
+ private static final Color CIRCLE_SAMPLE_COLOR = new Color(220, 20, 60, 230);
+ private static final double CIRCLE_SAMPLE_SIZE = 0.54d;
private static final double BOUNDARY_POINT_MERGE_THRESHOLD = 0.05;
private static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -49,6 +57,7 @@
private List<Obstacledge.Obstacle> currentObstacles;
private Rectangle2D.Double obstacleBounds;
private String selectedObstacleName;
+ private String currentObstacleLandNumber;
private String boundaryName;
private boolean boundaryPointsVisible;
private String currentBoundaryLandNumber;
@@ -65,6 +74,8 @@
private JLabel realtimeSpeedValueLabel;
private JLabel headingValueLabel;
private JLabel updateTimeValueLabel;
+ private CircleCaptureOverlay circleCaptureOverlay;
+ private final List<double[]> circleSampleMarkers = new ArrayList<>();
public MapRenderer(JPanel visualizationPanel) {
this.visualizationPanel = visualizationPanel;
@@ -218,6 +229,16 @@
Obstacledraw.drawObstacles(g2d, currentObstacles, scale, selectedObstacleName);
}
+ yulanzhangaiwu.renderPreview(g2d, scale);
+
+ if (!circleSampleMarkers.isEmpty()) {
+ drawCircleSampleMarkers(g2d, circleSampleMarkers, scale);
+ }
+
+ if (circleCaptureOverlay != null) {
+ drawCircleCaptureOverlay(g2d, circleCaptureOverlay, scale);
+ }
+
if (hasPlannedPath) {
drawCurrentPlannedPath(g2d);
}
@@ -296,6 +317,137 @@
lujingdraw.drawPlannedPath(g2d, currentPlannedPath, scale);
}
+ private void drawCircleSampleMarkers(Graphics2D g2d, List<double[]> markers, double scale) {
+ if (markers == null || markers.isEmpty()) {
+ return;
+ }
+ Shape markerShape;
+ double half = CIRCLE_SAMPLE_SIZE / 2.0;
+ g2d.setColor(CIRCLE_SAMPLE_COLOR);
+ g2d.setStroke(new BasicStroke((float) (1.2f / scale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ Font originalFont = g2d.getFont();
+ float baseSize = (float) Math.max(12f / scale, 9f);
+ float reducedSize = Math.max(baseSize / 3f, 3f);
+ Font labelFont = originalFont.deriveFont(reducedSize);
+ g2d.setFont(labelFont);
+ FontMetrics metrics = g2d.getFontMetrics();
+ for (double[] pt : markers) {
+ if (pt == null || pt.length < 2 || !Double.isFinite(pt[0]) || !Double.isFinite(pt[1])) {
+ continue;
+ }
+ double x = pt[0];
+ double y = pt[1];
+ markerShape = new Ellipse2D.Double(x - half, y - half, CIRCLE_SAMPLE_SIZE, CIRCLE_SAMPLE_SIZE);
+ g2d.fill(markerShape);
+ String label = String.format(Locale.US, "%.2f,%.2f", x, y);
+ int textWidth = metrics.stringWidth(label);
+ float textX = (float) (x - textWidth / 2.0);
+ float textY = (float) (y - half - 0.2d) - metrics.getDescent();
+ g2d.setColor(new Color(33, 37, 41, 220));
+ g2d.drawString(label, textX, textY);
+ g2d.setColor(CIRCLE_SAMPLE_COLOR);
+ }
+ g2d.setFont(originalFont);
+ }
+
+ private void drawCircleCaptureOverlay(Graphics2D g2d, CircleCaptureOverlay overlay, double scale) {
+ double diameter = overlay.radius * 2.0;
+ Ellipse2D outline = new Ellipse2D.Double(
+ overlay.centerX - overlay.radius,
+ overlay.centerY - overlay.radius,
+ diameter,
+ diameter);
+
+ Color fillColor = new Color(255, 152, 0, 80);
+ Color borderColor = new Color(255, 87, 34, 230);
+ Color centerColor = new Color(46, 139, 87, 230);
+
+ g2d.setColor(fillColor);
+ g2d.fill(outline);
+
+ g2d.setColor(borderColor);
+ g2d.setStroke(new BasicStroke((float) (1.8f / scale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ g2d.draw(outline);
+
+ double markerSize = 0.18d;
+ double centerMarkerSize = 0.22d;
+
+ Ellipse2D centerMarker = new Ellipse2D.Double(
+ overlay.centerX - centerMarkerSize / 2.0,
+ overlay.centerY - centerMarkerSize / 2.0,
+ centerMarkerSize,
+ centerMarkerSize);
+ g2d.setColor(centerColor);
+ g2d.fill(centerMarker);
+ }
+
+ public void showCircleCaptureOverlay(double centerX, double centerY, double radius, List<double[]> samplePoints) {
+ List<double[]> copies = new ArrayList<>();
+ if (samplePoints != null) {
+ for (double[] pt : samplePoints) {
+ if (pt == null || pt.length < 2) {
+ continue;
+ }
+ copies.add(new double[]{pt[0], pt[1]});
+ }
+ }
+ circleCaptureOverlay = new CircleCaptureOverlay(centerX, centerY, radius, copies);
+ updateCircleSampleMarkers(samplePoints);
+ if (visualizationPanel != null) {
+ visualizationPanel.repaint();
+ }
+ }
+
+ public void clearCircleCaptureOverlay() {
+ circleCaptureOverlay = null;
+ if (visualizationPanel != null) {
+ visualizationPanel.repaint();
+ }
+ }
+
+ public void updateCircleSampleMarkers(List<double[]> samplePoints) {
+ circleSampleMarkers.clear();
+ if (samplePoints != null) {
+ for (double[] pt : samplePoints) {
+ if (pt == null || pt.length < 2) {
+ continue;
+ }
+ double x = pt[0];
+ double y = pt[1];
+ if (!Double.isFinite(x) || !Double.isFinite(y)) {
+ continue;
+ }
+ circleSampleMarkers.add(new double[]{x, y});
+ }
+ }
+ if (visualizationPanel != null) {
+ visualizationPanel.repaint();
+ }
+ }
+
+ public void clearCircleSampleMarkers() {
+ if (!circleSampleMarkers.isEmpty()) {
+ circleSampleMarkers.clear();
+ if (visualizationPanel != null) {
+ visualizationPanel.repaint();
+ }
+ }
+ }
+
+ private static final class CircleCaptureOverlay {
+ final double centerX;
+ final double centerY;
+ final double radius;
+ final List<double[]> samplePoints;
+
+ CircleCaptureOverlay(double centerX, double centerY, double radius, List<double[]> samplePoints) {
+ this.centerX = centerX;
+ this.centerY = centerY;
+ this.radius = radius;
+ this.samplePoints = samplePoints;
+ }
+ }
+
private void showMowerInfo() {
Device device = Device.getGecaoji();
if (device == null) {
@@ -771,18 +923,24 @@
}
public void setCurrentObstacles(String obstaclesData, String landNumber) {
- if (landNumber == null) {
- clearObstacleData();
- if (!hasRenderableBoundary() && !hasRenderablePlannedPath()) {
- resetView();
- } else {
- visualizationPanel.repaint();
- }
- return;
- }
-
List<Obstacledge.Obstacle> parsed = parseObstacles(obstaclesData, landNumber);
- if (parsed.isEmpty()) {
+ applyObstaclesToRenderer(parsed, landNumber);
+ }
+
+ public void setCurrentObstacles(List<Obstacledge.Obstacle> obstacles, String landNumber) {
+ List<Obstacledge.Obstacle> cloned = cloneObstacles(obstacles, landNumber);
+ applyObstaclesToRenderer(cloned, landNumber);
+ }
+
+ private void applyObstaclesToRenderer(List<Obstacledge.Obstacle> obstacles, String landNumber) {
+ List<Obstacledge.Obstacle> safeList = obstacles != null ? obstacles : Collections.emptyList();
+ String normalizedLand = (landNumber != null) ? landNumber.trim() : null;
+
+ if (normalizedLand != null && !normalizedLand.isEmpty()) {
+ safeList = filterObstaclesForLand(safeList, normalizedLand);
+ }
+
+ if (normalizedLand == null || normalizedLand.isEmpty()) {
clearObstacleData();
if (!hasRenderableBoundary() && !hasRenderablePlannedPath()) {
resetView();
@@ -792,8 +950,19 @@
return;
}
- currentObstacles = parsed;
- obstacleBounds = convertObstacleBounds(Obstacledraw.getAllObstaclesBounds(parsed));
+ if (safeList.isEmpty()) {
+ clearObstacleData();
+ if (!hasRenderableBoundary() && !hasRenderablePlannedPath()) {
+ resetView();
+ } else {
+ visualizationPanel.repaint();
+ }
+ return;
+ }
+
+ currentObstacles = Collections.unmodifiableList(new ArrayList<>(safeList));
+ currentObstacleLandNumber = normalizedLand;
+ obstacleBounds = convertObstacleBounds(Obstacledraw.getAllObstaclesBounds(currentObstacles));
selectedObstacleName = null;
if (!hasRenderableBoundary() && !hasRenderablePlannedPath() && obstacleBounds != null) {
@@ -807,10 +976,150 @@
}
}
+ private List<Obstacledge.Obstacle> cloneObstacles(List<Obstacledge.Obstacle> obstacles, String landNumber) {
+ List<Obstacledge.Obstacle> result = new ArrayList<>();
+ if (obstacles == null || obstacles.isEmpty()) {
+ return result;
+ }
+
+ String normalizedLandNumber = landNumber != null ? landNumber.trim() : null;
+ Set<String> usedNames = new LinkedHashSet<>();
+ int fallbackIndex = 1;
+
+ for (Obstacledge.Obstacle source : obstacles) {
+ if (source == null) {
+ continue;
+ }
+
+ if (normalizedLandNumber != null && !normalizedLandNumber.isEmpty()) {
+ String sourcePlotId = source.getPlotId();
+ if (sourcePlotId != null && !sourcePlotId.trim().isEmpty()
+ && !normalizedLandNumber.equalsIgnoreCase(sourcePlotId.trim())) {
+ continue;
+ }
+ }
+
+ Obstacledge.ObstacleShape shape = source.getShape();
+ List<Obstacledge.XYCoordinate> xySource = source.getXyCoordinates();
+ if (shape == null || xySource == null) {
+ continue;
+ }
+
+ List<Obstacledge.XYCoordinate> xyCopy = copyXYCoordinates(xySource);
+ if (shape == Obstacledge.ObstacleShape.CIRCLE && xyCopy.size() < 2) {
+ continue;
+ }
+ if (shape == Obstacledge.ObstacleShape.POLYGON && xyCopy.size() < 3) {
+ continue;
+ }
+
+ String desiredName = source.getObstacleName();
+ if (desiredName == null || desiredName.trim().isEmpty()) {
+ desiredName = "闅滅鐗�" + fallbackIndex++;
+ }
+ String uniqueName = ensureUniqueName(usedNames, desiredName.trim());
+
+ Obstacledge.Obstacle copy = new Obstacledge.Obstacle(
+ normalizedLandNumber != null ? normalizedLandNumber : source.getPlotId(),
+ uniqueName,
+ shape
+ );
+
+ copy.setXyCoordinates(xyCopy);
+
+ List<Obstacledge.DMCoordinate> dmCopy = copyDMCoordinates(source.getOriginalCoordinates());
+ if (dmCopy.isEmpty()) {
+ populateDummyOriginalCoordinates(copy, xyCopy.size());
+ } else {
+ copy.setOriginalCoordinates(dmCopy);
+ }
+
+ result.add(copy);
+ }
+
+ return result;
+ }
+
+ private List<Obstacledge.Obstacle> filterObstaclesForLand(List<Obstacledge.Obstacle> obstacles, String landNumber) {
+ if (obstacles == null || obstacles.isEmpty()) {
+ return Collections.emptyList();
+ }
+ if (landNumber == null || landNumber.trim().isEmpty()) {
+ return Collections.emptyList();
+ }
+ String normalized = landNumber.trim();
+ List<Obstacledge.Obstacle> filtered = new ArrayList<>();
+ for (Obstacledge.Obstacle obstacle : obstacles) {
+ if (obstacle == null) {
+ continue;
+ }
+ String plotId = obstacle.getPlotId();
+ if (plotId == null || plotId.trim().isEmpty()) {
+ filtered.add(obstacle);
+ continue;
+ }
+ if (normalized.equalsIgnoreCase(plotId.trim())) {
+ filtered.add(obstacle);
+ }
+ }
+ return filtered;
+ }
+
+ private String ensureUniqueName(Set<String> usedNames, String preferredName) {
+ String base = (preferredName == null || preferredName.trim().isEmpty()) ? "闅滅鐗�" : preferredName.trim();
+ String normalized = base.toLowerCase(Locale.ROOT);
+ if (usedNames.add(normalized)) {
+ return base;
+ }
+ int suffix = 2;
+ while (true) {
+ String attempt = base + suffix;
+ String attemptKey = attempt.toLowerCase(Locale.ROOT);
+ if (usedNames.add(attemptKey)) {
+ return attempt;
+ }
+ suffix++;
+ }
+ }
+
+ private List<Obstacledge.XYCoordinate> copyXYCoordinates(List<Obstacledge.XYCoordinate> source) {
+ List<Obstacledge.XYCoordinate> copy = new ArrayList<>();
+ if (source == null) {
+ return copy;
+ }
+ for (Obstacledge.XYCoordinate coord : source) {
+ if (coord == null) {
+ continue;
+ }
+ double x = coord.getX();
+ double y = coord.getY();
+ if (!Double.isFinite(x) || !Double.isFinite(y)) {
+ continue;
+ }
+ copy.add(new Obstacledge.XYCoordinate(x, y));
+ }
+ return copy;
+ }
+
+ private List<Obstacledge.DMCoordinate> copyDMCoordinates(List<Obstacledge.DMCoordinate> source) {
+ List<Obstacledge.DMCoordinate> copy = new ArrayList<>();
+ if (source == null) {
+ return copy;
+ }
+ for (Obstacledge.DMCoordinate coord : source) {
+ if (coord == null) {
+ continue;
+ }
+ copy.add(new Obstacledge.DMCoordinate(coord.getDegreeMinute(), coord.getDirection()));
+ }
+ return copy;
+ }
+
private void clearObstacleData() {
currentObstacles = null;
obstacleBounds = null;
selectedObstacleName = null;
+ currentObstacleLandNumber = null;
}
private List<Obstacledge.Obstacle> parseObstacles(String obstaclesData, String landNumber) {
--
Gitblit v1.10.0