From 32c98d4855b6178554c787103dc956d161e152b3 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期五, 19 十二月 2025 19:45:30 +0800
Subject: [PATCH] 增加了异形分析逻辑
---
src/zhangaiwu/AddDikuai.java | 1124 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 955 insertions(+), 169 deletions(-)
diff --git a/src/zhangaiwu/AddDikuai.java b/src/zhangaiwu/AddDikuai.java
index 4feafe5..c7cb4bd 100644
--- a/src/zhangaiwu/AddDikuai.java
+++ b/src/zhangaiwu/AddDikuai.java
@@ -14,21 +14,26 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Comparator;
import java.awt.geom.Point2D;
+import baseStation.BaseStation;
import bianjie.jisuanmianjie;
import dikuai.Dikuai;
import dikuai.Dikuaiguanli;
-import gecaoji.Device;
import bianjie.bianjieguihua2;
import lujing.Lunjingguihua;
+import set.Setsys;
import ui.UIConfig;
import zhuye.MowerLocationData;
import zhuye.Shouye;
import zhuye.Coordinate;
+import zhuye.buttonset;
+import gecaoji.Device;
/**
* 鏂板鍦板潡瀵硅瘽妗� - 澶氭楠よ〃鍗曡璁�
@@ -48,6 +53,9 @@
private final Color LIGHT_TEXT = new Color(108, 117, 125);
private final Color BORDER_COLOR = new Color(222, 226, 230);
private final Color SUCCESS_COLOR = new Color(40, 167, 69);
+ private final Color ERROR_COLOR = new Color(220, 53, 69);
+ private static final String KEY_PATH_MESSAGE_TEXT = "__pathMessageText";
+ private static final String KEY_PATH_MESSAGE_SUCCESS = "__pathMessageSuccess";
// 姝ラ闈㈡澘
private JPanel mainPanel;
@@ -58,7 +66,10 @@
private JTextField landNumberField;
private JTextField areaNameField;
private JComboBox<String> mowingPatternCombo;
- private JSpinner mowingWidthSpinner;
+ private JTextField mowingWidthField; // 鍓茶崏鏈哄壊鍒�瀹藉害
+ private JTextField overlapDistanceField; // 鐩搁偦琛岄噸鍙犺窛绂�
+ private JTextField mowingSafetyDistanceField; // 鍓茶崏瀹夊叏璺濈
+ private JLabel calculatedMowingWidthLabel; // 璁$畻鍚庣殑鍓茶崏瀹藉害鏄剧ず
private JPanel previewPanel;
private Map<String, JPanel> drawingOptionPanels = new HashMap<>();
@@ -67,8 +78,12 @@
private JButton prevButton;
private JButton nextButton;
private JButton createButton;
+ private JButton previewButton;
+ private Component previewButtonSpacer;
private JLabel boundaryCountLabel;
private JPanel obstacleListContainer;
+ private JTextArea pathGenerationMessageArea;
+ private JPanel pathMessageWrapper;
// 鍦板潡鏁版嵁
private Map<String, String> dikuaiData = new HashMap<>();
@@ -281,10 +296,6 @@
formGroup.add(areaNameField);
formGroup.add(Box.createRigidArea(new Dimension(0, 8)));
formGroup.add(hintLabel);
-
- formGroup.add(Box.createRigidArea(new Dimension(0, 20)));
- JPanel obstacleSection = createObstacleSummarySection();
- formGroup.add(obstacleSection);
stepPanel.add(formGroup);
stepPanel.add(Box.createVerticalGlue());
@@ -362,93 +373,105 @@
private List<ObstacleSummary> loadExistingObstacles() {
List<ObstacleSummary> summaries = new ArrayList<>();
+ List<ExistingObstacle> obstacles = fetchExistingObstacleDetails();
- String landNumber = getPendingLandNumber();
- String raw = null;
- if (landNumber != null) {
- Dikuai dikuai = Dikuai.getDikuai(landNumber);
- if (dikuai != null) {
- raw = normalizeCoordinateValue(dikuai.getObstacleCoordinates());
- }
- }
- if (raw == null) {
- raw = normalizeCoordinateValue(dikuaiData.get("obstacleCoordinates"));
- }
- if (!isMeaningfulValue(raw)) {
+ if (obstacles.isEmpty()) {
return summaries;
}
- String normalized = stripInlineComment(raw);
- if (normalized.isEmpty()) {
- return summaries;
- }
-
- List<String> entries = splitObstacleEntries(normalized);
- int defaultIndex = 1;
-
- for (String entry : entries) {
- String trimmedEntry = stripInlineComment(entry);
- if (trimmedEntry.isEmpty()) {
+ for (ExistingObstacle obstacle : obstacles) {
+ if (obstacle == null) {
continue;
}
-
- String nameToken = null;
- String shapeToken = null;
- String coordsSection = trimmedEntry;
-
- if (trimmedEntry.contains("::")) {
- String[] parts = trimmedEntry.split("::", 3);
- if (parts.length == 3) {
- nameToken = parts[0].trim();
- shapeToken = parts[1].trim();
- coordsSection = parts[2].trim();
- }
- } else if (trimmedEntry.contains("@")) {
- String[] parts = trimmedEntry.split("@", 3);
- if (parts.length == 3) {
- nameToken = parts[0].trim();
- shapeToken = parts[1].trim();
- coordsSection = parts[2].trim();
- } else if (parts.length == 2) {
- shapeToken = parts[0].trim();
- coordsSection = parts[1].trim();
- }
- } else if (trimmedEntry.contains(":")) {
- String[] parts = trimmedEntry.split(":", 3);
- if (parts.length == 3) {
- nameToken = parts[0].trim();
- shapeToken = parts[1].trim();
- coordsSection = parts[2].trim();
- } else if (parts.length == 2) {
- if (looksLikeShapeToken(parts[0])) {
- shapeToken = parts[0].trim();
- coordsSection = parts[1].trim();
- } else {
- nameToken = parts[0].trim();
- coordsSection = parts[1].trim();
- }
- }
- }
-
- String sanitizedCoords = sanitizeCoordinateString(coordsSection);
- if (!isMeaningfulValue(sanitizedCoords)) {
+ String name = obstacle.getName();
+ if (!isMeaningfulValue(name)) {
continue;
}
-
- String resolvedName;
- if (nameToken != null && !nameToken.isEmpty()) {
- resolvedName = nameToken;
- } else {
- resolvedName = "闅滅鐗�" + defaultIndex++;
- }
-
- String displayCoords = truncateCoordinateForDisplay(sanitizedCoords, 12);
- summaries.add(new ObstacleSummary(resolvedName, sanitizedCoords, displayCoords));
+ String coords = obstacle.getDisplayCoordinates();
+ String fullCoords = isMeaningfulValue(coords) ? coords.trim() : "";
+ String preview = buildCoordinatePreview(fullCoords, 20);
+ summaries.add(new ObstacleSummary(name.trim(), fullCoords, preview));
}
return summaries;
}
+ private List<ExistingObstacle> fetchExistingObstacleDetails() {
+ File configFile = new File("Obstacledge.properties");
+ if (!configFile.exists()) {
+ return Collections.emptyList();
+ }
+
+ List<ExistingObstacle> result = new ArrayList<>();
+ try {
+ Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
+ if (!manager.loadFromFile(configFile.getAbsolutePath())) {
+ return Collections.emptyList();
+ }
+
+ for (Obstacledge.Plot plot : manager.getPlots()) {
+ if (plot == null) {
+ continue;
+ }
+ String landNumber = isMeaningfulValue(plot.getPlotId()) ? plot.getPlotId().trim() : "";
+ List<Obstacledge.Obstacle> plotObstacles = plot.getObstacles();
+ if (plotObstacles == null || plotObstacles.isEmpty()) {
+ continue;
+ }
+ for (Obstacledge.Obstacle obstacle : plotObstacles) {
+ if (obstacle == null) {
+ continue;
+ }
+ String name = obstacle.getObstacleName();
+ if (!isMeaningfulValue(name)) {
+ continue;
+ }
+ String coords = extractObstacleCoordinates(obstacle);
+ result.add(new ExistingObstacle(landNumber, name.trim(), coords));
+ }
+ }
+ } catch (Exception ex) {
+ System.err.println("鍔犺浇宸叉湁闅滅鐗╁け璐�: " + ex.getMessage());
+ return Collections.emptyList();
+ }
+
+ if (result.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ result.sort(Comparator.comparing(ExistingObstacle::getName, String.CASE_INSENSITIVE_ORDER));
+ return result;
+ }
+
+ private String extractObstacleCoordinates(Obstacledge.Obstacle obstacle) {
+ if (obstacle == null) {
+ return "";
+ }
+ String xy = obstacle.getXyCoordsString();
+ if (isMeaningfulValue(xy)) {
+ return xy.trim();
+ }
+ String original = obstacle.getOriginalCoordsString();
+ if (isMeaningfulValue(original)) {
+ return original.trim();
+ }
+ return "";
+ }
+
+ private String buildCoordinatePreview(String coords, int keepLength) {
+ if (!isMeaningfulValue(coords)) {
+ return "鏃犲潗鏍�";
+ }
+ String sanitized = sanitizeCoordinateString(coords);
+ if (sanitized.length() <= keepLength) {
+ return sanitized;
+ }
+ if (keepLength <= 0) {
+ return "...";
+ }
+ return sanitized.substring(0, keepLength) + "...";
+ }
+
private List<String> splitObstacleEntries(String data) {
List<String> entries = new ArrayList<>();
if (data.indexOf('|') >= 0) {
@@ -543,6 +566,30 @@
return displayCoords;
}
}
+
+ private static final class ExistingObstacle {
+ private final String landNumber;
+ private final String name;
+ private final String coordinates;
+
+ ExistingObstacle(String landNumber, String name, String coordinates) {
+ this.landNumber = landNumber != null ? landNumber : "";
+ this.name = name != null ? name : "";
+ this.coordinates = coordinates != null ? coordinates : "";
+ }
+
+ String getLandNumber() {
+ return landNumber;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ String getDisplayCoordinates() {
+ return coordinates;
+ }
+ }
private JPanel createStep2Panel() {
JPanel stepPanel = new JPanel();
@@ -696,8 +743,9 @@
if (!optionPanel.isEnabled()) {
return;
}
- selectDrawingOption(optionPanel, type);
- startEndDrawingBtn.setEnabled(true); // 閫夋嫨鍚庡惎鐢ㄦ寜閽�
+ if (selectDrawingOption(optionPanel, type, true)) {
+ startEndDrawingBtn.setEnabled(true); // 閫夋嫨鍚庡惎鐢ㄦ寜閽�
+ }
}
@Override
@@ -719,7 +767,15 @@
return optionPanel;
}
- private void selectDrawingOption(JPanel optionPanel, String type) {
+ private boolean selectDrawingOption(JPanel optionPanel, String type, boolean userTriggered) {
+ if (optionPanel == null) {
+ return false;
+ }
+ if (userTriggered && "handheld".equalsIgnoreCase(type) && !hasConfiguredHandheldMarker()) {
+ JOptionPane.showMessageDialog(this, "璇峰厛鍘荤郴缁熻缃坊鍔犱究鎼烘墦鐐瑰櫒缂栧彿", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ return false;
+ }
+
// 閲嶇疆涔嬪墠閫変腑鐨勯�夐」
if (selectedOptionPanel != null) {
selectedOptionPanel.setBorder(BorderFactory.createLineBorder(BORDER_COLOR, 2));
@@ -729,7 +785,7 @@
((JLabel) oldTitle).setForeground(TEXT_COLOR);
}
}
-
+
// 璁剧疆鏂扮殑閫変腑鐘舵��
optionPanel.setBorder(BorderFactory.createLineBorder(PRIMARY_COLOR, 3));
optionPanel.setBackground(PRIMARY_LIGHT);
@@ -738,9 +794,15 @@
((JLabel) titleObj).setForeground(PRIMARY_COLOR);
}
selectedOptionPanel = optionPanel;
-
+
// 淇濆瓨閫夋嫨
dikuaiData.put("drawingMethod", type);
+ return true;
+ }
+
+ private boolean hasConfiguredHandheldMarker() {
+ String handheldId = Setsys.getPropertyValue("handheldMarkerId");
+ return handheldId != null && !handheldId.trim().isEmpty();
}
private void toggleDrawing() {
@@ -840,7 +902,7 @@
settingsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
// 鍓茶崏妯″紡閫夋嫨
- JPanel patternPanel = createFormGroup("鍓茶崏妯″紡", "閫夋嫨鍓茶崏璺緞鐨勭敓鎴愭ā寮�");
+ JPanel patternPanel = createFormGroupWithoutHint("鍓茶崏妯″紡");
mowingPatternCombo = new JComboBox<>(new String[]{"骞宠绾�", "铻烘棆寮�"});
mowingPatternCombo.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
mowingPatternCombo.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
@@ -872,29 +934,27 @@
patternPanel.add(mowingPatternCombo);
settingsPanel.add(patternPanel);
- settingsPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
- // 鍓茶崏瀹藉害璁剧疆
- JPanel widthPanel = createFormGroup("鍓茶崏瀹藉害", "璁剧疆鍓茶崏鏈哄崟娆″壊鑽夌殑瀹藉害");
+ // 鍓茶崏鏈哄壊鍒�瀹藉害璁剧疆
+ JPanel widthPanel = createFormGroupWithoutHint("鍓茶崏鏈哄壊鍒�瀹藉害");
JPanel widthInputPanel = new JPanel(new BorderLayout());
widthInputPanel.setBackground(WHITE);
widthInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
widthInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
- SpinnerNumberModel widthModel = new SpinnerNumberModel(40, 20, 60, 1);
- mowingWidthSpinner = new JSpinner(widthModel);
- mowingWidthSpinner.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
- JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) mowingWidthSpinner.getEditor();
- editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+ mowingWidthField = new JTextField("0.40");
+ mowingWidthField.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+ mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(BORDER_COLOR, 2),
BorderFactory.createEmptyBorder(10, 12, 10, 12)
));
- // 娣诲姞寰皟鍣ㄧ劍鐐规晥鏋�
- mowingWidthSpinner.addFocusListener(new FocusAdapter() {
+ // 娣诲姞鏂囨湰妗嗙劍鐐规晥鏋滃拰鍙樺寲鐩戝惉
+ mowingWidthField.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
- editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+ mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
BorderFactory.createEmptyBorder(10, 12, 10, 12)
));
@@ -902,27 +962,156 @@
@Override
public void focusLost(FocusEvent e) {
- editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+ mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(BORDER_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+ updateCalculatedMowingWidth();
+ }
+ });
+
+ JLabel unitLabel = new JLabel("绫�");
+ unitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+ unitLabel.setForeground(LIGHT_TEXT);
+ unitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
+
+ widthInputPanel.add(mowingWidthField, BorderLayout.CENTER);
+ widthInputPanel.add(unitLabel, BorderLayout.EAST);
+
+ widthPanel.add(widthInputPanel);
+ settingsPanel.add(widthPanel);
+ settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // 鐩搁偦琛岄噸鍙犺窛绂昏缃�
+ JPanel overlapPanel = createFormGroupWithoutHint("鐩搁偦琛岄噸鍙犺窛绂�");
+ JPanel overlapInputPanel = new JPanel(new BorderLayout());
+ overlapInputPanel.setBackground(WHITE);
+ overlapInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
+ overlapInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ overlapDistanceField = new JTextField("0.06");
+ overlapDistanceField.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+ overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(BORDER_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+
+ // 娣诲姞鏂囨湰妗嗙劍鐐规晥鏋滃拰鍙樺寲鐩戝惉
+ overlapDistanceField.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(BORDER_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+ updateCalculatedMowingWidth();
+ }
+ });
+
+ JLabel overlapUnitLabel = new JLabel("绫�");
+ overlapUnitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+ overlapUnitLabel.setForeground(LIGHT_TEXT);
+ overlapUnitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
+
+ overlapInputPanel.add(overlapDistanceField, BorderLayout.CENTER);
+ overlapInputPanel.add(overlapUnitLabel, BorderLayout.EAST);
+
+ overlapPanel.add(overlapInputPanel);
+ settingsPanel.add(overlapPanel);
+ settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // 鍓茶崏瀹藉害鏄剧ず锛堣嚜鍔ㄨ绠楋紝涓嶅彲淇敼锛�
+ JPanel calculatedWidthPanel = createFormGroup("鍓茶崏瀹藉害", "鍓茶崏瀹藉害 = 鍓茶崏鏈哄壊鍒�瀹藉害 - 閲嶅彔璺濈锛堣嚜鍔ㄨ绠楋級");
+ JPanel calculatedWidthDisplayPanel = new JPanel(new BorderLayout());
+ calculatedWidthDisplayPanel.setBackground(LIGHT_GRAY);
+ calculatedWidthDisplayPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
+ calculatedWidthDisplayPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ calculatedWidthDisplayPanel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(BORDER_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+
+ calculatedMowingWidthLabel = new JLabel("0.00 绫�");
+ calculatedMowingWidthLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+ calculatedMowingWidthLabel.setForeground(TEXT_COLOR);
+ calculatedWidthDisplayPanel.add(calculatedMowingWidthLabel, BorderLayout.CENTER);
+
+ calculatedWidthPanel.add(calculatedWidthDisplayPanel);
+ settingsPanel.add(calculatedWidthPanel);
+ settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // 鍓茶崏瀹夊叏璺濈
+ JPanel safetyDistancePanel = createFormGroupWithoutHint("鍓茶崏瀹夊叏璺濈");
+ JPanel safetyDistanceInputPanel = new JPanel(new BorderLayout());
+ safetyDistanceInputPanel.setBackground(WHITE);
+ safetyDistanceInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
+ safetyDistanceInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ // 鑾峰彇榛樿鍊�
+ String defaultSafetyDistance = "0.5"; // 榛樿鍊�
+ try {
+ Device device = Device.getGecaoji();
+ if (device != null) {
+ String safetyDistance = device.getMowingSafetyDistance();
+ if (safetyDistance != null && !safetyDistance.trim().isEmpty() && !"-1".equals(safetyDistance.trim())) {
+ defaultSafetyDistance = safetyDistance.trim();
+ }
+ }
+ } catch (Exception e) {
+ // 濡傛灉鑾峰彇澶辫触锛屼娇鐢ㄩ粯璁ゅ��
+ }
+
+ mowingSafetyDistanceField = new JTextField(defaultSafetyDistance);
+ mowingSafetyDistanceField.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+ mowingSafetyDistanceField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(BORDER_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+
+ // 娣诲姞鏂囨湰妗嗙劍鐐规晥鏋�
+ mowingSafetyDistanceField.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ mowingSafetyDistanceField.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
+ BorderFactory.createEmptyBorder(10, 12, 10, 12)
+ ));
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ mowingSafetyDistanceField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(BORDER_COLOR, 2),
BorderFactory.createEmptyBorder(10, 12, 10, 12)
));
}
});
- JLabel unitLabel = new JLabel("鍘樼背");
- unitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
- unitLabel.setForeground(LIGHT_TEXT);
- unitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
+ JLabel safetyDistanceUnitLabel = new JLabel("绫�");
+ safetyDistanceUnitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+ safetyDistanceUnitLabel.setForeground(LIGHT_TEXT);
+ safetyDistanceUnitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
- widthInputPanel.add(mowingWidthSpinner, BorderLayout.CENTER);
- widthInputPanel.add(unitLabel, BorderLayout.EAST);
+ safetyDistanceInputPanel.add(mowingSafetyDistanceField, BorderLayout.CENTER);
+ safetyDistanceInputPanel.add(safetyDistanceUnitLabel, BorderLayout.EAST);
- widthPanel.add(widthInputPanel);
- settingsPanel.add(widthPanel);
+ safetyDistancePanel.add(safetyDistanceInputPanel);
+ settingsPanel.add(safetyDistancePanel);
settingsPanel.add(Box.createRigidArea(new Dimension(0, 25)));
stepPanel.add(settingsPanel);
+ // 鍒濆鍖栬绠楀悗鐨勫壊鑽夊搴�
+ updateCalculatedMowingWidth();
+
JButton generatePathButton = createPrimaryButton("鐢熸垚鍓茶崏璺緞", 16);
generatePathButton.setAlignmentX(Component.LEFT_ALIGNMENT);
generatePathButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 55));
@@ -930,11 +1119,69 @@
stepPanel.add(Box.createRigidArea(new Dimension(0, 20)));
stepPanel.add(generatePathButton);
+ stepPanel.add(Box.createRigidArea(new Dimension(0, 12)));
+
+ pathMessageWrapper = new JPanel(new BorderLayout());
+ pathMessageWrapper.setAlignmentX(Component.LEFT_ALIGNMENT);
+ pathMessageWrapper.setBackground(PRIMARY_LIGHT);
+ pathMessageWrapper.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(PRIMARY_COLOR, 1),
+ BorderFactory.createEmptyBorder(12, 12, 12, 12)
+ ));
+ pathMessageWrapper.setVisible(false);
+
+ pathGenerationMessageArea = new JTextArea();
+ pathGenerationMessageArea.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+ pathGenerationMessageArea.setForeground(TEXT_COLOR);
+ pathGenerationMessageArea.setOpaque(false);
+ pathGenerationMessageArea.setEditable(false);
+ pathGenerationMessageArea.setLineWrap(true);
+ pathGenerationMessageArea.setWrapStyleWord(true);
+ pathGenerationMessageArea.setFocusable(false);
+ pathGenerationMessageArea.setBorder(null);
+
+ pathMessageWrapper.add(pathGenerationMessageArea, BorderLayout.CENTER);
+ stepPanel.add(pathMessageWrapper);
stepPanel.add(Box.createVerticalGlue());
return stepPanel;
}
+ /**
+ * 鏇存柊璁$畻鍚庣殑鍓茶崏瀹藉害鏄剧ず
+ */
+ private void updateCalculatedMowingWidth() {
+ if (calculatedMowingWidthLabel == null || mowingWidthField == null || overlapDistanceField == null) {
+ return;
+ }
+
+ try {
+ String widthText = mowingWidthField.getText().trim();
+ String overlapText = overlapDistanceField.getText().trim();
+
+ if (widthText.isEmpty() || overlapText.isEmpty()) {
+ calculatedMowingWidthLabel.setText("0.00 绫�");
+ return;
+ }
+
+ double bladeWidthMeters = Double.parseDouble(widthText);
+ double overlapMeters = Double.parseDouble(overlapText);
+ double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+
+ if (calculatedWidthMeters <= 0) {
+ calculatedMowingWidthLabel.setText("鏃犳晥锛堝壊鍒�瀹藉害闇�澶т簬閲嶅彔璺濈锛�");
+ calculatedMowingWidthLabel.setForeground(ERROR_COLOR);
+ } else {
+ calculatedMowingWidthLabel.setText(String.format(Locale.US, "%.2f 绫�", calculatedWidthMeters));
+ calculatedMowingWidthLabel.setForeground(TEXT_COLOR);
+ }
+ } catch (NumberFormatException e) {
+ calculatedMowingWidthLabel.setText("0.00 绫�");
+ } catch (Exception e) {
+ calculatedMowingWidthLabel.setText("0.00 绫�");
+ }
+ }
+
private JPanel createInstructionPanel(String text) {
JPanel instructionPanel = new JPanel(new BorderLayout());
instructionPanel.setBackground(PRIMARY_LIGHT);
@@ -985,10 +1232,30 @@
return formGroup;
}
+
+ private JPanel createFormGroupWithoutHint(String label) {
+ JPanel formGroup = new JPanel();
+ formGroup.setLayout(new BoxLayout(formGroup, BoxLayout.Y_AXIS));
+ formGroup.setBackground(WHITE);
+ formGroup.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ JLabel nameLabel = new JLabel(label);
+ nameLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+ nameLabel.setForeground(TEXT_COLOR);
+ nameLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ formGroup.add(nameLabel);
+ formGroup.add(Box.createRigidArea(new Dimension(0, 8)));
+
+ return formGroup;
+ }
private void generateMowingPath() {
if (!dikuaiData.containsKey("boundaryDrawn")) {
JOptionPane.showMessageDialog(this, "璇峰厛瀹屾垚杈圭晫缁樺埗鍚庡啀鐢熸垚璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("璇峰厛瀹屾垚杈圭晫缁樺埗鍚庡啀鐢熸垚璺緞銆�", false);
+ setPathAvailability(false);
showStep(2);
return;
}
@@ -1002,15 +1269,16 @@
}
if (boundaryCoords == null) {
JOptionPane.showMessageDialog(this, "鏈壘鍒版湁鏁堢殑鍦板潡杈圭晫鍧愭爣锛屾棤娉曠敓鎴愯矾寰�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
- }
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鏈壘鍒版湁鏁堢殑鍦板潡杈圭晫鍧愭爣锛屾棤娉曠敓鎴愯矾寰勩��", false);
+ setPathAvailability(false);
return;
}
String obstacleCoords = null;
- if (dikuai != null) {
- obstacleCoords = normalizeCoordinateValue(dikuai.getObstacleCoordinates());
+ String landNumber = getPendingLandNumber();
+ if (isMeaningfulValue(landNumber)) {
+ obstacleCoords = normalizeCoordinateValue(resolveObstaclePayloadFromConfig(landNumber));
}
if (obstacleCoords == null) {
obstacleCoords = normalizeCoordinateValue(dikuaiData.get("obstacleCoordinates"));
@@ -1019,25 +1287,79 @@
String patternDisplay = (String) mowingPatternCombo.getSelectedItem();
dikuaiData.put("mowingPattern", patternDisplay);
- Object widthObj = mowingWidthSpinner.getValue();
- if (!(widthObj instanceof Number)) {
- JOptionPane.showMessageDialog(this, "鍓茶崏瀹藉害杈撳叆鏃犳晥", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
- }
+ String widthText = mowingWidthField.getText().trim();
+ if (widthText.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害涓嶈兘涓虹┖", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害涓嶈兘涓虹┖锛岃閲嶆柊杈撳叆銆�", false);
+ setPathAvailability(false);
return;
}
- double widthCm = ((Number) widthObj).doubleValue();
- if (widthCm <= 0) {
- JOptionPane.showMessageDialog(this, "鍓茶崏瀹藉害蹇呴』澶т簬0", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
- }
+ double bladeWidthMeters;
+ try {
+ bladeWidthMeters = Double.parseDouble(widthText);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害杈撳叆鏃犳晥", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害杈撳叆鏃犳晥锛岃閲嶆柊杈撳叆銆�", false);
+ setPathAvailability(false);
return;
}
- dikuaiData.put("mowingWidth", widthObj.toString());
+ if (bladeWidthMeters <= 0) {
+ JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害蹇呴』澶т簬0", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害蹇呴』澶т簬0锛岃閲嶆柊璁剧疆銆�", false);
+ setPathAvailability(false);
+ return;
+ }
+ // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害锛堢背锛�
+ dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+
+ // 鑾峰彇閲嶅彔璺濈
+ String overlapText = overlapDistanceField.getText().trim();
+ if (overlapText.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负绌�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负绌猴紝璇烽噸鏂拌緭鍏ャ��", false);
+ setPathAvailability(false);
+ return;
+ }
+ double overlapMeters;
+ try {
+ overlapMeters = Double.parseDouble(overlapText);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂昏緭鍏ユ棤鏁�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂昏緭鍏ユ棤鏁堬紝璇烽噸鏂拌緭鍏ャ��", false);
+ setPathAvailability(false);
+ return;
+ }
+ if (overlapMeters < 0) {
+ JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负璐熸暟", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负璐熸暟锛岃閲嶆柊璁剧疆銆�", false);
+ setPathAvailability(false);
+ return;
+ }
+
+ // 淇濆瓨閲嶅彔璺濈鍒板湴鍧楁暟鎹�
+ dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+
+ // 璁$畻瀹為檯浣跨敤鐨勫壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+ double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+ if (calculatedWidthMeters <= 0) {
+ JOptionPane.showMessageDialog(this, "璁$畻鍚庣殑鍓茶崏瀹藉害蹇呴』澶т簬0锛堝壊鍒�瀹藉害蹇呴』澶т簬閲嶅彔璺濈锛�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("璁$畻鍚庣殑鍓茶崏瀹藉害蹇呴』澶т簬0锛岃璋冩暣鍓插垁瀹藉害鎴栭噸鍙犺窛绂汇��", false);
+ setPathAvailability(false);
+ return;
+ }
- String widthMeters = String.format(Locale.US, "%.2f", widthCm / 100.0);
+ // 淇濆瓨鍓茶崏瀹藉害锛堣绠楀悗鐨勫�硷紝杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹癸級
+ double calculatedWidthCm = calculatedWidthMeters * 100.0;
+ dikuaiData.put("mowingWidth", String.format(Locale.US, "%.0f", calculatedWidthCm));
+
+ String widthMeters = String.format(Locale.US, "%.2f", calculatedWidthMeters);
String plannerMode = resolvePlannerMode(patternDisplay);
try {
@@ -1050,46 +1372,190 @@
String plannedPath = Lunjingguihua.formatPathSegments(segments);
if (!isMeaningfulValue(plannedPath)) {
JOptionPane.showMessageDialog(this, "鐢熸垚鍓茶崏璺緞澶辫触: 鐢熸垚缁撴灉涓虹┖", "閿欒", JOptionPane.ERROR_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
- }
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐢熸垚鍓茶崏璺緞澶辫触锛氱敓鎴愮粨鏋滀负绌恒��", false);
+ setPathAvailability(false);
return;
}
- dikuaiData.put("plannedPath", plannedPath);
- if (createButton != null) {
- createButton.setEnabled(true);
+ if (isMeaningfulValue(boundaryCoords)) {
+ dikuaiData.put("boundaryCoordinates", boundaryCoords);
}
- JOptionPane.showMessageDialog(this,
- "宸叉牴鎹綋鍓嶈缃敓鎴愬壊鑽夎矾寰勶紝鍏辩敓鎴� " + segments.size() + " 娈点��",
- "鎴愬姛",
- JOptionPane.INFORMATION_MESSAGE);
+ if (isMeaningfulValue(obstacleCoords)) {
+ dikuaiData.put("obstacleCoordinates", obstacleCoords);
+ }
+ dikuaiData.put("plannedPath", plannedPath);
+ setPathAvailability(true);
+ showPathGenerationMessage(
+ "宸叉牴鎹綋鍓嶈缃敓鎴愬壊鑽夎矾寰勶紝鍏辩敓鎴� " + segments.size() + " 娈点�俓n鐐瑰嚮鈥滈瑙堚�濇寜閽彲鍦ㄤ富椤甸潰鏌ョ湅鏁堟灉銆�",
+ true);
} catch (IllegalArgumentException ex) {
JOptionPane.showMessageDialog(this, "鐢熸垚鍓茶崏璺緞澶辫触: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
- }
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐢熸垚鍓茶崏璺緞澶辫触锛�" + ex.getMessage(), false);
+ setPathAvailability(false);
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "鐢熸垚鍓茶崏璺緞鏃跺彂鐢熷紓甯�: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
- if (createButton != null) {
- createButton.setEnabled(false);
+ dikuaiData.remove("plannedPath");
+ showPathGenerationMessage("鐢熸垚鍓茶崏璺緞鏃跺彂鐢熷紓甯革細" + ex.getMessage(), false);
+ setPathAvailability(false);
+ }
+ }
+
+ private void previewMowingPath() {
+ if (!hasGeneratedPath()) {
+ showPathGenerationMessage("璇峰厛鐢熸垚鍓茶崏璺緞鍚庡啀棰勮銆�", false);
+ setPathAvailability(false);
+ return;
+ }
+
+ persistStep3Inputs();
+
+ String landNumber = getPendingLandNumber();
+ String trimmedAreaName = areaNameField.getText() != null ? areaNameField.getText().trim() : "";
+ String displayAreaName = isMeaningfulValue(trimmedAreaName) ? trimmedAreaName : landNumber;
+
+ String plannedPath = dikuaiData.get("plannedPath");
+ if (!isMeaningfulValue(plannedPath)) {
+ showPathGenerationMessage("璇峰厛鐢熸垚鍓茶崏璺緞鍚庡啀棰勮銆�", false);
+ setPathAvailability(false);
+ return;
+ }
+
+ String boundary = null;
+ Dikuai pending = getOrCreatePendingDikuai();
+ if (pending != null) {
+ boundary = normalizeCoordinateValue(pending.getBoundaryCoordinates());
+ }
+ if (boundary == null) {
+ boundary = normalizeCoordinateValue(dikuaiData.get("boundaryCoordinates"));
+ }
+
+ String obstacles = normalizeCoordinateValue(dikuaiData.get("obstacleCoordinates"));
+ if (!isMeaningfulValue(obstacles)) {
+ obstacles = resolveObstaclePayloadFromConfig(landNumber);
+ if (isMeaningfulValue(obstacles)) {
+ dikuaiData.put("obstacleCoordinates", obstacles);
+ }
+ }
+
+ Shouye shouye = Shouye.getInstance();
+ if (shouye == null) {
+ JOptionPane.showMessageDialog(this, "鏃犳硶鎵撳紑涓婚〉闈紝璇风◢鍚庨噸璇�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ dikuaiData.put("areaName", trimmedAreaName);
+ if (isMeaningfulValue(boundary)) {
+ dikuaiData.put("boundaryCoordinates", boundary);
+ }
+
+ pendingLandNumber = landNumber;
+ captureSessionSnapshot();
+
+ resumeRequested = true;
+ boolean started = shouye.startMowingPathPreview(
+ landNumber,
+ displayAreaName,
+ boundary,
+ obstacles,
+ plannedPath,
+ AddDikuai::resumeFromPreview
+ );
+ if (!started) {
+ resumeRequested = false;
+ JOptionPane.showMessageDialog(this, "鏃犳硶鍚姩棰勮锛岃绋嶅悗鍐嶈瘯", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ closePreviewAndDispose();
+ }
+
+ private void persistStep3Inputs() {
+ String trimmedName = areaNameField.getText() != null ? areaNameField.getText().trim() : "";
+ dikuaiData.put("areaName", trimmedName);
+
+ if (mowingPatternCombo != null) {
+ Object selection = mowingPatternCombo.getSelectedItem();
+ if (selection != null) {
+ dikuaiData.put("mowingPattern", selection.toString());
+ }
+ }
+
+ // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害
+ if (mowingWidthField != null) {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ if (!bladeWidthText.isEmpty()) {
+ try {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+ } catch (NumberFormatException e) {
+ // 濡傛灉瑙f瀽澶辫触锛岀洿鎺ヤ繚瀛樻枃鏈�
+ dikuaiData.put("mowingBladeWidth", bladeWidthText);
+ }
+ }
+ }
+
+ // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂�
+ if (overlapDistanceField != null) {
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!overlapText.isEmpty()) {
+ try {
+ double overlapMeters = Double.parseDouble(overlapText);
+ dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+ } catch (NumberFormatException e) {
+ // 濡傛灉瑙f瀽澶辫触锛岀洿鎺ヤ繚瀛樻枃鏈�
+ dikuaiData.put("mowingOverlapDistance", overlapText);
+ }
+ }
+ }
+
+ // 璁$畻骞朵繚瀛樺壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+ if (mowingWidthField != null && overlapDistanceField != null) {
+ try {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ double overlapMeters = Double.parseDouble(overlapText);
+ double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+ if (calculatedWidthMeters > 0) {
+ // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+ int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+ dikuaiData.put("mowingWidth", Integer.toString(widthCm));
+ }
+ }
+ } catch (NumberFormatException e) {
+ // 濡傛灉璁$畻澶辫触锛屼笉淇濆瓨鍓茶崏瀹藉害
}
}
}
+
+ private void captureSessionSnapshot() {
+ if (activeSession == null) {
+ activeSession = new DrawingSession();
+ }
+ String landNumber = getPendingLandNumber();
+ activeSession.landNumber = landNumber;
+ activeSession.areaName = areaNameField.getText() != null ? areaNameField.getText().trim() : "";
+ activeSession.drawingCompleted = true;
+ activeSession.data = new HashMap<>(dikuaiData);
+ }
+
+ private void closePreviewAndDispose() {
+ setVisible(false);
+ dispose();
+ }
private JButton createPrimaryButton(String text, int fontSize) {
- JButton button = new JButton(text);
+ JButton button = buttonset.createStyledButton(text, PRIMARY_COLOR);
button.setFont(new Font("寰蒋闆呴粦", Font.BOLD, fontSize));
- button.setBackground(PRIMARY_COLOR);
- button.setForeground(WHITE);
button.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(PRIMARY_DARK, 2),
BorderFactory.createEmptyBorder(12, 25, 12, 25)
));
- button.setFocusPainted(false);
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
- // 鎸夐挳鎮仠鏁堟灉
+
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
@@ -1097,7 +1563,7 @@
button.setBackground(PRIMARY_DARK);
}
}
-
+
@Override
public void mouseExited(MouseEvent e) {
if (button.isEnabled()) {
@@ -1105,9 +1571,47 @@
}
}
});
-
+
return button;
}
+
+ private void showPathGenerationMessage(String message, boolean success) {
+ if (pathGenerationMessageArea == null || pathMessageWrapper == null) {
+ return;
+ }
+ String display = message == null ? "" : message.trim();
+ if (display.isEmpty()) {
+ dikuaiData.remove(KEY_PATH_MESSAGE_TEXT);
+ dikuaiData.remove(KEY_PATH_MESSAGE_SUCCESS);
+ } else {
+ dikuaiData.put(KEY_PATH_MESSAGE_TEXT, display);
+ dikuaiData.put(KEY_PATH_MESSAGE_SUCCESS, success ? "true" : "false");
+ }
+ pathGenerationMessageArea.setText(display);
+ Color borderColor = success ? PRIMARY_COLOR : ERROR_COLOR;
+ Color textColor = success ? PRIMARY_DARK : ERROR_COLOR;
+ Color backgroundColor = success ? PRIMARY_LIGHT : new Color(255, 235, 238);
+ pathGenerationMessageArea.setForeground(textColor);
+ pathMessageWrapper.setBackground(backgroundColor);
+ pathMessageWrapper.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(borderColor, 1),
+ BorderFactory.createEmptyBorder(12, 12, 12, 12)
+ ));
+ pathMessageWrapper.setVisible(!display.isEmpty());
+ pathMessageWrapper.revalidate();
+ pathMessageWrapper.repaint();
+ }
+
+ private void setPathAvailability(boolean available) {
+ boolean effective = available && currentStep == 3;
+ if (createButton != null) {
+ createButton.setEnabled(effective);
+ }
+ if (previewButton != null) {
+ boolean visible = previewButton.isVisible();
+ previewButton.setEnabled(effective && visible);
+ }
+ }
private JPanel createButtonPanel() {
JPanel buttonPanel = new JPanel();
@@ -1115,25 +1619,32 @@
buttonPanel.setBackground(WHITE);
buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
- prevButton = new JButton("涓婁竴姝�");
+ prevButton = buttonset.createStyledButton("涓婁竴姝�", MEDIUM_GRAY);
prevButton.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
- prevButton.setBackground(MEDIUM_GRAY);
prevButton.setForeground(TEXT_COLOR);
prevButton.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(BORDER_COLOR, 2),
BorderFactory.createEmptyBorder(10, 25, 10, 25)
));
- prevButton.setFocusPainted(false);
prevButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
nextButton = createPrimaryButton("涓嬩竴姝�", 16);
createButton = createPrimaryButton("淇濆瓨", 16);
createButton.setVisible(false);
- createButton.setEnabled(false);
+ createButton.setEnabled(false);
+
+ previewButton = createPrimaryButton("棰勮", 16);
+ previewButton.setVisible(false);
+ previewButton.setEnabled(false);
+
+ previewButtonSpacer = Box.createHorizontalStrut(15);
+ previewButtonSpacer.setVisible(false);
buttonPanel.add(prevButton);
buttonPanel.add(Box.createHorizontalGlue());
buttonPanel.add(nextButton);
+ buttonPanel.add(previewButtonSpacer);
+ buttonPanel.add(previewButton);
buttonPanel.add(Box.createHorizontalStrut(15));
buttonPanel.add(createButton);
@@ -1185,14 +1696,40 @@
return true;
}
- private static String buildOriginalBoundaryString() {
- if (Coordinate.coordinates == null || Coordinate.coordinates.isEmpty()) {
+ private static List<Coordinate> sanitizeCoordinateList(List<Coordinate> source) {
+ if (source == null || source.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<Coordinate> snapshot = new ArrayList<>();
+ for (Coordinate coordinate : source) {
+ if (coordinate != null) {
+ snapshot.add(coordinate);
+ }
+ }
+ if (snapshot.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ DecimalFormat latLonFormat = new DecimalFormat("0.000000");
+ LinkedHashMap<String, Coordinate> unique = new LinkedHashMap<>();
+ for (Coordinate coord : snapshot) {
+ double lat = convertToDecimalDegree(coord.getLatitude(), coord.getLatDirection());
+ double lon = convertToDecimalDegree(coord.getLongitude(), coord.getLonDirection());
+ String key = latLonFormat.format(lat) + "," + latLonFormat.format(lon);
+ unique.putIfAbsent(key, coord);
+ }
+ return new ArrayList<>(unique.values());
+ }
+
+ private static String buildOriginalBoundaryString(List<Coordinate> coordinates) {
+ if (coordinates == null || coordinates.isEmpty()) {
return "-1";
}
StringBuilder sb = new StringBuilder();
DecimalFormat latLonFormat = new DecimalFormat("0.000000");
DecimalFormat elevationFormat = new DecimalFormat("0.00");
- for (Coordinate coord : Coordinate.coordinates) {
+ for (Coordinate coord : coordinates) {
double lat = convertToDecimalDegree(coord.getLatitude(), coord.getLatDirection());
double lon = convertToDecimalDegree(coord.getLongitude(), coord.getLonDirection());
double elevation = coord.getElevation();
@@ -1259,6 +1796,30 @@
return isMeaningfulValue(dikuaiData.get("plannedPath"));
}
+ private String resolveObstaclePayloadFromConfig(String landNumber) {
+ if (!isMeaningfulValue(landNumber)) {
+ return null;
+ }
+ try {
+ File configFile = new File("Obstacledge.properties");
+ if (!configFile.exists()) {
+ return null;
+ }
+ Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
+ if (!manager.loadFromFile(configFile.getAbsolutePath())) {
+ return null;
+ }
+ Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
+ if (plot == null) {
+ return null;
+ }
+ return Obstacledge.buildPlannerPayload(plot.getObstacles());
+ } catch (Exception ex) {
+ System.err.println("鍔犺浇闅滅鐗╅厤缃け璐�: " + ex.getMessage());
+ return null;
+ }
+ }
+
private static String normalizeCoordinateValue(String value) {
return isMeaningfulValue(value) ? value.trim() : null;
}
@@ -1272,8 +1833,14 @@
}
private static BoundarySnapshotResult computeBoundarySnapshot() {
- int count = Coordinate.coordinates != null ? Coordinate.coordinates.size() : 0;
- if (count < 3) {
+ List<Coordinate> uniqueCoordinates;
+ synchronized (Coordinate.coordinates) {
+ uniqueCoordinates = sanitizeCoordinateList(Coordinate.coordinates);
+ Coordinate.coordinates.clear();
+ Coordinate.coordinates.addAll(uniqueCoordinates);
+ }
+
+ if (uniqueCoordinates.size() < 3) {
return BoundarySnapshotResult.failure("閲囬泦鐨勮竟鐣岀偣涓嶈冻锛屾棤娉曠敓鎴愬湴鍧楄竟鐣�", JOptionPane.WARNING_MESSAGE);
}
@@ -1282,9 +1849,9 @@
return BoundarySnapshotResult.failure("褰撳墠鍦板潡闈㈢Н涓�0锛屾棤娉曠户缁�", JOptionPane.WARNING_MESSAGE);
}
- Device device = new Device();
- device.initFromProperties();
- String baseStationCoordinates = normalizeCoordinateValue(device.getBaseStationCoordinates());
+ BaseStation baseStation = new BaseStation();
+ baseStation.load();
+ String baseStationCoordinates = normalizeCoordinateValue(baseStation.getInstallationCoordinates());
if (!isMeaningfulValue(baseStationCoordinates)) {
return BoundarySnapshotResult.failure("鏈幏鍙栧埌鏈夋晥鐨勫熀鍑嗙珯鍧愭爣锛岃鍏堝湪鍩哄噯绔欑鐞嗕腑璁剧疆", JOptionPane.WARNING_MESSAGE);
}
@@ -1297,7 +1864,7 @@
return BoundarySnapshotResult.failure("鐢熸垚鍦板潡杈圭晫澶辫触: " + ex.getMessage(), JOptionPane.ERROR_MESSAGE);
}
- String originalBoundary = buildOriginalBoundaryString();
+ String originalBoundary = buildOriginalBoundaryString(uniqueCoordinates);
DecimalFormat areaFormat = new DecimalFormat("0.00");
String areaString = areaFormat.format(area);
@@ -1345,6 +1912,10 @@
// 鍒涘缓鍦板潡鎸夐挳
createButton.addActionListener(e -> createDikuai());
+
+ if (previewButton != null) {
+ previewButton.addActionListener(e -> previewMowingPath());
+ }
// 鍏抽棴瀵硅瘽妗�
addWindowListener(new WindowAdapter() {
@@ -1358,10 +1929,6 @@
private void showStep(int step) {
currentStep = step;
cardLayout.show(stepsPanel, "step" + step);
-
- if (step == 1) {
- updateObstacleSummary();
- }
// 鏇存柊鎸夐挳鐘舵��
updateButtonState(step);
@@ -1373,11 +1940,24 @@
if (step < 3) {
nextButton.setVisible(true);
createButton.setVisible(false);
- createButton.setEnabled(false);
+ setPathAvailability(false);
+ if (previewButton != null) {
+ previewButton.setVisible(false);
+ previewButton.setEnabled(false);
+ }
+ if (previewButtonSpacer != null) {
+ previewButtonSpacer.setVisible(false);
+ }
} else {
nextButton.setVisible(false);
createButton.setVisible(true);
- createButton.setEnabled(hasGeneratedPath());
+ if (previewButton != null) {
+ previewButton.setVisible(true);
+ }
+ if (previewButtonSpacer != null) {
+ previewButtonSpacer.setVisible(true);
+ }
+ setPathAvailability(hasGeneratedPath());
}
Container parent = prevButton.getParent();
@@ -1419,7 +1999,53 @@
case 3:
dikuaiData.put("mowingPattern", (String) mowingPatternCombo.getSelectedItem());
- dikuaiData.put("mowingWidth", mowingWidthSpinner.getValue().toString());
+
+ // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害
+ if (mowingWidthField != null) {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ if (!bladeWidthText.isEmpty()) {
+ try {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+ } catch (NumberFormatException e) {
+ dikuaiData.put("mowingBladeWidth", bladeWidthText);
+ }
+ }
+ }
+
+ // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂�
+ if (overlapDistanceField != null) {
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!overlapText.isEmpty()) {
+ try {
+ double overlapMeters = Double.parseDouble(overlapText);
+ dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+ } catch (NumberFormatException e) {
+ dikuaiData.put("mowingOverlapDistance", overlapText);
+ }
+ }
+ }
+
+ // 璁$畻骞朵繚瀛樺壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+ if (mowingWidthField != null && overlapDistanceField != null) {
+ try {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ double overlapMeters = Double.parseDouble(overlapText);
+ double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+ if (calculatedWidthMeters > 0) {
+ // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+ int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+ dikuaiData.put("mowingWidth", Integer.toString(widthCm));
+ }
+ }
+ } catch (NumberFormatException e) {
+ // 濡傛灉璁$畻澶辫触锛屼笉淇濆瓨鍓茶崏瀹藉害
+ }
+ }
+
if (!hasGeneratedPath()) {
JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚鍓茶崏璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
return false;
@@ -1649,7 +2275,7 @@
if (method != null) {
JPanel panel = drawingOptionPanels.get(method);
if (panel != null) {
- selectDrawingOption(panel, method);
+ selectDrawingOption(panel, method, false);
}
}
@@ -1674,6 +2300,101 @@
showStep(1);
hideBoundaryPointSummary();
}
+
+ restoreGeneratedPathState(session);
+ }
+
+ private void restoreGeneratedPathState(DrawingSession session) {
+ if (session == null || session.data == null) {
+ showPathGenerationMessage("", true);
+ return;
+ }
+
+ Map<String, String> data = session.data;
+
+ if (mowingPatternCombo != null) {
+ String pattern = data.get("mowingPattern");
+ if (pattern != null) {
+ ComboBoxModel<String> model = mowingPatternCombo.getModel();
+ for (int i = 0; i < model.getSize(); i++) {
+ String candidate = model.getElementAt(i);
+ if (pattern.equals(candidate)) {
+ mowingPatternCombo.setSelectedIndex(i);
+ break;
+ }
+ }
+ }
+ }
+
+ // 鎭㈠鍓茶崏鏈哄壊鍒�瀹藉害锛堜紭鍏堜粠mowingBladeWidth鑾峰彇锛�
+ if (mowingWidthField != null) {
+ String bladeWidth = data.get("mowingBladeWidth");
+ if (isMeaningfulValue(bladeWidth)) {
+ try {
+ double bladeWidthMeters = Double.parseDouble(bladeWidth.trim());
+ mowingWidthField.setText(String.format(Locale.US, "%.2f", bladeWidthMeters));
+ } catch (NumberFormatException ignored) {
+ // 濡傛灉mowingBladeWidth涓嶅瓨鍦ㄦ垨瑙f瀽澶辫触锛屽皾璇曚粠mowingWidth鎭㈠
+ String width = data.get("mowingWidth");
+ if (isMeaningfulValue(width)) {
+ try {
+ // 濡傛灉瀛樺偍鐨勬槸鍘樼背锛岃浆鎹负绫虫樉绀�
+ double parsed = Double.parseDouble(width.trim());
+ // 鍋囪濡傛灉鍊煎ぇ浜�10锛屽垯鏄帢绫筹紝闇�瑕佽浆鎹负绫筹紱鍚﹀垯宸茬粡鏄背
+ double widthMeters = parsed > 10 ? parsed / 100.0 : parsed;
+ mowingWidthField.setText(String.format(Locale.US, "%.2f", widthMeters));
+ } catch (NumberFormatException ignored2) {
+ // 淇濇寔褰撳墠鍊�
+ }
+ }
+ }
+ } else {
+ // 濡傛灉mowingBladeWidth涓嶅瓨鍦紝灏濊瘯浠巑owingWidth鎭㈠
+ String width = data.get("mowingWidth");
+ if (isMeaningfulValue(width)) {
+ try {
+ // 濡傛灉瀛樺偍鐨勬槸鍘樼背锛岃浆鎹负绫虫樉绀�
+ double parsed = Double.parseDouble(width.trim());
+ // 鍋囪濡傛灉鍊煎ぇ浜�10锛屽垯鏄帢绫筹紝闇�瑕佽浆鎹负绫筹紱鍚﹀垯宸茬粡鏄背
+ double widthMeters = parsed > 10 ? parsed / 100.0 : parsed;
+ mowingWidthField.setText(String.format(Locale.US, "%.2f", widthMeters));
+ } catch (NumberFormatException ignored) {
+ // 淇濇寔褰撳墠鍊�
+ }
+ }
+ }
+ }
+
+ if (overlapDistanceField != null) {
+ String overlap = data.get("mowingOverlapDistance");
+ if (isMeaningfulValue(overlap)) {
+ try {
+ double overlapMeters = Double.parseDouble(overlap.trim());
+ overlapDistanceField.setText(String.format(Locale.US, "%.2f", overlapMeters));
+ } catch (NumberFormatException ignored) {
+ // 淇濇寔褰撳墠鍊�
+ }
+ }
+ }
+
+ boolean hasPath = isMeaningfulValue(data.get("plannedPath"));
+ if (!hasPath) {
+ showPathGenerationMessage("", true);
+ if (currentStep == 3) {
+ setPathAvailability(false);
+ }
+ return;
+ }
+
+ String message = data.get(KEY_PATH_MESSAGE_TEXT);
+ boolean success = !"false".equalsIgnoreCase(data.get(KEY_PATH_MESSAGE_SUCCESS));
+ showStep(3);
+ if (isMeaningfulValue(message)) {
+ showPathGenerationMessage(message, success);
+ } else {
+ showPathGenerationMessage("宸茬敓鎴愬壊鑽夎矾寰勶紝鍙偣鍑烩�滈瑙堚�濇寜閽煡鐪嬫晥鏋溿��", true);
+ }
+ setPathAvailability(true);
}
public static void finishDrawingSession() {
@@ -1707,6 +2428,19 @@
Component parent = shouye != null ? shouye : null;
showAddDikuaiDialog(parent);
}
+
+ public static void resumeFromPreview() {
+ Shouye shouye = Shouye.getInstance();
+ if (shouye != null) {
+ shouye.exitMowingPathPreview();
+ }
+ if (activeSession == null) {
+ return;
+ }
+ resumeRequested = true;
+ Component parent = shouye != null ? shouye : null;
+ SwingUtilities.invokeLater(() -> showAddDikuaiDialog(parent));
+ }
private void createDikuai() {
if (!validateCurrentStep()) {
@@ -1745,8 +2479,60 @@
if (dikuaiData.containsKey("mowingPattern")) {
dikuai.setMowingPattern(dikuaiData.get("mowingPattern"));
}
+
+ // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害锛堜紭鍏堜粠dikuaiData鑾峰彇锛屽惁鍒欎粠TextField鑾峰彇锛�
+ if (dikuaiData.containsKey("mowingBladeWidth")) {
+ dikuai.setMowingBladeWidth(dikuaiData.get("mowingBladeWidth"));
+ } else if (mowingWidthField != null) {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ if (!bladeWidthText.isEmpty()) {
+ try {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ dikuai.setMowingBladeWidth(String.format(Locale.US, "%.2f", bladeWidthMeters));
+ } catch (NumberFormatException e) {
+ dikuai.setMowingBladeWidth(bladeWidthText);
+ }
+ }
+ }
+
+ // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂伙紙浼樺厛浠巇ikuaiData鑾峰彇锛屽惁鍒欎粠TextField鑾峰彇锛�
+ if (dikuaiData.containsKey("mowingOverlapDistance")) {
+ dikuai.setMowingOverlapDistance(dikuaiData.get("mowingOverlapDistance"));
+ } else if (overlapDistanceField != null) {
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!overlapText.isEmpty()) {
+ try {
+ double overlapMeters = Double.parseDouble(overlapText);
+ dikuai.setMowingOverlapDistance(String.format(Locale.US, "%.2f", overlapMeters));
+ } catch (NumberFormatException e) {
+ dikuai.setMowingOverlapDistance(overlapText);
+ }
+ }
+ }
+
+ // 淇濆瓨鍓茶崏瀹藉害锛堣绠楀悗鐨勫�硷紝浼樺厛浠巇ikuaiData鑾峰彇锛�
if (dikuaiData.containsKey("mowingWidth")) {
dikuai.setMowingWidth(dikuaiData.get("mowingWidth"));
+ } else {
+ // 濡傛灉娌℃湁鍦╠ikuaiData涓紝鍒欎粠TextField璁$畻
+ if (mowingWidthField != null && overlapDistanceField != null) {
+ try {
+ String bladeWidthText = mowingWidthField.getText().trim();
+ String overlapText = overlapDistanceField.getText().trim();
+ if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+ double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+ double overlapMeters = Double.parseDouble(overlapText);
+ double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+ if (calculatedWidthMeters > 0) {
+ // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+ int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+ dikuai.setMowingWidth(Integer.toString(widthCm));
+ }
+ }
+ } catch (NumberFormatException e) {
+ // 濡傛灉璁$畻澶辫触锛屼繚鎸佸師鏈夊�兼垨浣跨敤榛樿鍊�
+ }
+ }
}
String plannedPath = dikuaiData.get("plannedPath");
--
Gitblit v1.10.0