张世豪
22 小时以前 1175f5fbe8fd832943880bfc37c0e2a451a0688a
src/dikuai/Dikuaiguanli.java
@@ -1,5 +1,4 @@
package dikuai;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@@ -20,8 +19,7 @@
import java.util.Collections;
import java.util.Objects;
import java.util.Properties;
import lujing.Lunjingguihua;
import java.util.Locale;
import lujing.MowingPathGenerationPage;
import publicway.Fuzhibutton;
import publicway.Lookbutton;
@@ -271,14 +269,17 @@
      contentPanel.add(mowingPatternPanel);
      contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      // 割草机割刀宽度
      // 割草机割刀宽度(单位:米,保留2位小数)
      String mowingBladeWidthValue = dikuai.getMowingBladeWidth();
      String displayBladeWidth = "未设置";
      if (mowingBladeWidthValue != null && !"-1".equals(mowingBladeWidthValue) && !mowingBladeWidthValue.trim().isEmpty()) {
         try {
            double bladeWidthMeters = Double.parseDouble(mowingBladeWidthValue.trim());
            double bladeWidthCm = bladeWidthMeters * 100.0;
            displayBladeWidth = String.format("%.2f厘米", bladeWidthCm);
            // 如果值大于100,认为是厘米,需要转换为米
            if (bladeWidthMeters > 100) {
               bladeWidthMeters = bladeWidthMeters / 100.0;
            }
            displayBladeWidth = String.format(Locale.US, "%.2fm", bladeWidthMeters);
         } catch (NumberFormatException e) {
            displayBladeWidth = "未设置";
         }
@@ -287,10 +288,18 @@
      contentPanel.add(mowingBladeWidthPanel);
      contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
      // 割草宽度(单位:米,保留2位小数)
      String mowingWidthValue = dikuai.getMowingWidth();
      String displayWidth = "未设置";
      if (mowingWidthValue != null && !"-1".equals(mowingWidthValue) && !mowingWidthValue.trim().isEmpty()) {
         displayWidth = mowingWidthValue + "厘米";
         try {
            double widthCm = Double.parseDouble(mowingWidthValue.trim());
            // 将厘米转换为米,保留2位小数
            double widthMeters = widthCm / 100.0;
            displayWidth = String.format(Locale.US, "%.2fm", widthMeters);
         } catch (NumberFormatException e) {
            displayWidth = "未设置";
         }
      }
      JPanel mowingWidthPanel = createCardInfoItem("割草宽度:", displayWidth);
      contentPanel.add(mowingWidthPanel);
@@ -306,7 +315,7 @@
            if (distanceMeters > 100) {
               distanceMeters = distanceMeters / 100.0;
            }
            displaySafetyDistance = String.format("%.2f米", distanceMeters);
            displaySafetyDistance = String.format(Locale.US, "%.2fm", distanceMeters);
         } catch (NumberFormatException e) {
            displaySafetyDistance = "未设置";
         }
@@ -1265,6 +1274,11 @@
         public boolean savePlannedPath(Dikuai dikuai, String value) {
            return saveFieldAndRefresh(dikuai, "plannedPath", value);
         }
         @Override
         public boolean saveMowingSafetyDistance(Dikuai dikuai, String value) {
            return saveFieldAndRefresh(dikuai, "mowingSafetyDistance", value);
         }
      };
      // 显示路径规划页面
@@ -1307,14 +1321,8 @@
         }
      }
      String modeValue = sanitizeValueOrNull(dikuai.getMowingPattern());
      String initialGenerated = attemptMowingPathPreview(
         boundaryValue,
         obstacleValue,
         widthValue,
         modeValue,
         this,
         false
      );
      // 不再预先生成路径,由路径规划页面处理
      String initialGenerated = null;
      showMowingPathDialog(dikuai, baseStationValue, boundaryValue, obstacleValue, widthValue, modeValue, initialGenerated);
   }
@@ -1354,6 +1362,11 @@
         public boolean savePlannedPath(Dikuai dikuai, String value) {
            return saveFieldAndRefresh(dikuai, "plannedPath", value);
         }
         @Override
         public boolean saveMowingSafetyDistance(Dikuai dikuai, String value) {
            return saveFieldAndRefresh(dikuai, "mowingSafetyDistance", value);
         }
      };
      
      // 使用新的独立页面类
@@ -1372,78 +1385,19 @@
      dialog.setVisible(true);
   }
   private String attemptMowingPathPreview(
      String boundaryInput,
      String obstacleInput,
      String widthCmInput,
      String modeInput,
      Component parentComponent,
      boolean showMessages) {
      String boundary = sanitizeValueOrNull(boundaryInput);
      if (boundary == null) {
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "当前地块未设置边界坐标,无法生成路径", "提示", JOptionPane.WARNING_MESSAGE);
         }
         return null;
      }
      String rawWidth = widthCmInput != null ? widthCmInput.trim() : "";
      String widthStr = sanitizeWidthString(widthCmInput);
      if (widthStr == null) {
         if (showMessages) {
            String message = rawWidth.isEmpty() ? "请先设置割草宽度(厘米)" : "割草宽度格式不正确";
            JOptionPane.showMessageDialog(parentComponent, message, "提示", JOptionPane.WARNING_MESSAGE);
         }
         return null;
      }
      double widthCm;
      try {
         widthCm = Double.parseDouble(widthStr);
      } catch (NumberFormatException ex) {
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "割草宽度格式不正确", "提示", JOptionPane.WARNING_MESSAGE);
         }
         return null;
      }
      if (widthCm <= 0) {
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "割草宽度必须大于0", "提示", JOptionPane.WARNING_MESSAGE);
         }
         return null;
      }
      double widthMeters = widthCm / 100.0d;
      String plannerWidth = BigDecimal.valueOf(widthMeters)
         .setScale(3, RoundingMode.HALF_UP)
         .stripTrailingZeros()
         .toPlainString();
      String obstacles = sanitizeValueOrNull(obstacleInput);
      if (obstacles != null) {
         obstacles = obstacles.replace("\r\n", " ").replace('\r', ' ').replace('\n', ' ');
      }
      String mode = normalizeExistingMowingPattern(modeInput);
      try {
         String generated = Lunjingguihua.generatePathFromStrings(boundary, obstacles, plannerWidth, mode);
         String trimmed = generated != null ? generated.trim() : "";
         if (trimmed.isEmpty()) {
            if (showMessages) {
               JOptionPane.showMessageDialog(parentComponent, "未生成有效的割草路径,请检查地块数据", "提示", JOptionPane.INFORMATION_MESSAGE);
            }
            return null;
         }
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "割草路径已生成", "成功", JOptionPane.INFORMATION_MESSAGE);
         }
         return trimmed;
      } catch (IllegalArgumentException ex) {
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "生成割草路径失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
         }
      } catch (Exception ex) {
         if (showMessages) {
            JOptionPane.showMessageDialog(parentComponent, "生成割草路径时发生异常: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
         }
      }
      return null;
   }
   /**
    * 尝试生成割草路径预览
    * 用于在对话框中实时预览或生成路径,包含参数校验和错误提示逻辑
    *
    * @param boundaryInput 地块边界坐标字符串
    * @param obstacleInput 障碍物坐标字符串
    * @param widthCmInput 割草宽度(厘米)
    * @param modeInput 割草模式(平行/螺旋)
    * @param parentComponent 用于显示提示框的父组件
    * @param showMessages 是否显示成功/失败的提示框
    * @return 生成的路径字符串,如果生成失败或校验未通过则返回 null
    */
   private JTextArea createInfoTextArea(String text, boolean editable, int rows) {
      JTextArea area = new JTextArea(text);
@@ -1636,6 +1590,9 @@
            return false;
         }
         // 同时保存到 dikuai.properties
         saveFieldAndRefresh(dikuai, "obstacleCoordinates", obstaclePayload);
         obstacleSummaryCache = loadObstacleSummaries();
         boolean isCurrent = landNumber.equals(currentWorkLandNumber);
         loadDikuaiData();