张世豪
18 小时以前 1175f5fbe8fd832943880bfc37c0e2a451a0688a
src/dikuai/Dikuaiguanli.java
@@ -1,5 +1,4 @@
package dikuai;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@@ -21,8 +20,6 @@
import java.util.Objects;
import java.util.Properties;
import java.util.Locale;
import lujing.Lunjingguihua;
import lujing.MowingPathGenerationPage;
import publicway.Fuzhibutton;
import publicway.Lookbutton;
@@ -1277,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);
         }
      };
      // 显示路径规划页面
@@ -1319,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);
   }
@@ -1366,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);
         }
      };
      
      // 使用新的独立页面类
@@ -1384,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);
@@ -1648,6 +1590,9 @@
            return false;
         }
         // 同时保存到 dikuai.properties
         saveFieldAndRefresh(dikuai, "obstacleCoordinates", obstaclePayload);
         obstacleSummaryCache = loadObstacleSummaries();
         boolean isCurrent = landNumber.equals(currentWorkLandNumber);
         loadDikuaiData();