| | |
| | | import dikuai.Dikuaiguanli; |
| | | 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; |
| | | |
| | | /** |
| | | * 新增地块对话框 - 多步骤表单设计 |
| | |
| | | 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<>(); |
| | | |
| | |
| | | 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()); |
| | |
| | | if (!optionPanel.isEnabled()) { |
| | | return; |
| | | } |
| | | selectDrawingOption(optionPanel, type); |
| | | startEndDrawingBtn.setEnabled(true); // 选择后启用按钮 |
| | | if (selectDrawingOption(optionPanel, type, true)) { |
| | | startEndDrawingBtn.setEnabled(true); // 选择后启用按钮 |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | 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)); |
| | |
| | | ((JLabel) oldTitle).setForeground(TEXT_COLOR); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 设置新的选中状态 |
| | | optionPanel.setBorder(BorderFactory.createLineBorder(PRIMARY_COLOR, 3)); |
| | | optionPanel.setBackground(PRIMARY_LIGHT); |
| | |
| | | ((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() { |
| | |
| | | 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)); |
| | |
| | | |
| | | 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) |
| | | )); |
| | |
| | | |
| | | @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)); |
| | |
| | | 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); |
| | |
| | | |
| | | 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")) { |
| | |
| | | String patternDisplay = (String) mowingPatternCombo.getSelectedItem(); |
| | | dikuaiData.put("mowingPattern", patternDisplay); |
| | | |
| | | Object widthObj = mowingWidthSpinner.getValue(); |
| | | if (!(widthObj instanceof Number)) { |
| | | JOptionPane.showMessageDialog(this, "割草宽度输入无效", "提示", JOptionPane.WARNING_MESSAGE); |
| | | String widthText = mowingWidthField.getText().trim(); |
| | | if (widthText.isEmpty()) { |
| | | JOptionPane.showMessageDialog(this, "割草机割刀宽度不能为空", "提示", JOptionPane.WARNING_MESSAGE); |
| | | dikuaiData.remove("plannedPath"); |
| | | showPathGenerationMessage("割草宽度输入无效,请重新输入。", false); |
| | | showPathGenerationMessage("割草机割刀宽度不能为空,请重新输入。", false); |
| | | setPathAvailability(false); |
| | | return; |
| | | } |
| | | double widthCm = ((Number) widthObj).doubleValue(); |
| | | if (widthCm <= 0) { |
| | | JOptionPane.showMessageDialog(this, "割草宽度必须大于0", "提示", JOptionPane.WARNING_MESSAGE); |
| | | double bladeWidthMeters; |
| | | try { |
| | | bladeWidthMeters = Double.parseDouble(widthText); |
| | | } catch (NumberFormatException e) { |
| | | JOptionPane.showMessageDialog(this, "割草机割刀宽度输入无效", "提示", JOptionPane.WARNING_MESSAGE); |
| | | dikuaiData.remove("plannedPath"); |
| | | showPathGenerationMessage("割草宽度必须大于0,请重新设置。", false); |
| | | 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 { |
| | |
| | | } |
| | | } |
| | | |
| | | if (mowingWidthSpinner != null) { |
| | | Object widthValue = mowingWidthSpinner.getValue(); |
| | | if (widthValue instanceof Number) { |
| | | int widthInt = ((Number) widthValue).intValue(); |
| | | dikuaiData.put("mowingWidth", Integer.toString(widthInt)); |
| | | } else if (widthValue != null) { |
| | | dikuaiData.put("mowingWidth", widthValue.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) { |
| | | // 如果计算失败,不保存割草宽度 |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | 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) { |
| | |
| | | button.setBackground(PRIMARY_DARK); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void mouseExited(MouseEvent e) { |
| | | if (button.isEnabled()) { |
| | |
| | | } |
| | | } |
| | | }); |
| | | |
| | | |
| | | return button; |
| | | } |
| | | |
| | |
| | | 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); |
| | |
| | | private void showStep(int step) { |
| | | currentStep = step; |
| | | cardLayout.show(stepsPanel, "step" + step); |
| | | |
| | | if (step == 1) { |
| | | updateObstacleSummary(); |
| | | } |
| | | |
| | | // 更新按钮状态 |
| | | updateButtonState(step); |
| | |
| | | |
| | | 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; |
| | |
| | | if (method != null) { |
| | | JPanel panel = drawingOptionPanels.get(method); |
| | | if (panel != null) { |
| | | selectDrawingOption(panel, method); |
| | | selectDrawingOption(panel, method, false); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | if (mowingWidthSpinner != null) { |
| | | String width = data.get("mowingWidth"); |
| | | if (isMeaningfulValue(width)) { |
| | | // 恢复割草机割刀宽度(优先从mowingBladeWidth获取) |
| | | if (mowingWidthField != null) { |
| | | String bladeWidth = data.get("mowingBladeWidth"); |
| | | if (isMeaningfulValue(bladeWidth)) { |
| | | try { |
| | | double parsed = Double.parseDouble(width.trim()); |
| | | SpinnerNumberModel model = (SpinnerNumberModel) mowingWidthSpinner.getModel(); |
| | | int min = ((Number) model.getMinimum()).intValue(); |
| | | int max = ((Number) model.getMaximum()).intValue(); |
| | | int rounded = (int) Math.round(parsed); |
| | | if (rounded < min) { |
| | | rounded = min; |
| | | } else if (rounded > max) { |
| | | rounded = max; |
| | | double bladeWidthMeters = Double.parseDouble(bladeWidth.trim()); |
| | | mowingWidthField.setText(String.format(Locale.US, "%.2f", bladeWidthMeters)); |
| | | } catch (NumberFormatException ignored) { |
| | | // 如果mowingBladeWidth不存在或解析失败,尝试从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) { |
| | | // 保持当前值 |
| | | } |
| | | } |
| | | mowingWidthSpinner.setValue(rounded); |
| | | } |
| | | } else { |
| | | // 如果mowingBladeWidth不存在,尝试从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 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) { |
| | | // 保持当前值 |
| | | } |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 保存相邻行重叠距离(优先从dikuaiData获取,否则从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); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 保存割草宽度(计算后的值,优先从dikuaiData获取) |
| | | if (dikuaiData.containsKey("mowingWidth")) { |
| | | dikuai.setMowingWidth(dikuaiData.get("mowingWidth")); |
| | | } else { |
| | | // 如果没有在dikuaiData中,则从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"); |