| | |
| | | import dikuai.Dikuaiguanli; |
| | | import bianjie.bianjieguihua2; |
| | | import lujing.Lunjingguihua; |
| | | import publicway.buttonset; |
| | | import set.Setsys; |
| | | import ui.UIConfig; |
| | | import zhuye.MowerLocationData; |
| | | import zhuye.Shouye; |
| | | import zhuye.Coordinate; |
| | | import zhuye.buttonset; |
| | | import gecaoji.Device; |
| | | |
| | | /** |
| | | * 新增地块对话框 - 多步骤表单设计 |
| | |
| | | private JComboBox<String> mowingPatternCombo; |
| | | private JTextField mowingWidthField; // 割草机割刀宽度 |
| | | private JTextField overlapDistanceField; // 相邻行重叠距离 |
| | | private JTextField mowingSafetyDistanceField; // 割草安全距离 |
| | | private JLabel calculatedMowingWidthLabel; // 计算后的割草宽度显示 |
| | | private JPanel previewPanel; |
| | | private Map<String, JPanel> drawingOptionPanels = new HashMap<>(); |
| | |
| | | final boolean success; |
| | | final String errorMessage; |
| | | final String originalBoundary; |
| | | final String originalBoundaryXY; |
| | | final String optimizedBoundary; |
| | | final String areaSqMeters; |
| | | final String baseStationCoordinates; |
| | |
| | | private BoundarySnapshotResult(boolean success, |
| | | String errorMessage, |
| | | String originalBoundary, |
| | | String originalBoundaryXY, |
| | | String optimizedBoundary, |
| | | String areaSqMeters, |
| | | String baseStationCoordinates, |
| | |
| | | this.success = success; |
| | | this.errorMessage = errorMessage; |
| | | this.originalBoundary = originalBoundary; |
| | | this.originalBoundaryXY = originalBoundaryXY; |
| | | this.optimizedBoundary = optimizedBoundary; |
| | | this.areaSqMeters = areaSqMeters; |
| | | this.baseStationCoordinates = baseStationCoordinates; |
| | | this.messageType = messageType; |
| | | } |
| | | |
| | | static BoundarySnapshotResult success(String original, String optimized, String area, String baseStation) { |
| | | return new BoundarySnapshotResult(true, null, original, optimized, area, baseStation, JOptionPane.INFORMATION_MESSAGE); |
| | | static BoundarySnapshotResult success(String original, String originalXY, String optimized, String area, String baseStation) { |
| | | return new BoundarySnapshotResult(true, null, original, originalXY, optimized, area, baseStation, JOptionPane.INFORMATION_MESSAGE); |
| | | } |
| | | |
| | | static BoundarySnapshotResult failure(String message, int messageType) { |
| | | return new BoundarySnapshotResult(false, message, null, null, null, null, messageType); |
| | | return new BoundarySnapshotResult(false, message, null, null, null, null, null, messageType); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | 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 safetyDistanceUnitLabel = new JLabel("米"); |
| | | safetyDistanceUnitLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); |
| | | safetyDistanceUnitLabel.setForeground(LIGHT_TEXT); |
| | | safetyDistanceUnitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0)); |
| | | |
| | | safetyDistanceInputPanel.add(mowingSafetyDistanceField, BorderLayout.CENTER); |
| | | safetyDistanceInputPanel.add(safetyDistanceUnitLabel, BorderLayout.EAST); |
| | | |
| | | safetyDistancePanel.add(safetyDistanceInputPanel); |
| | | settingsPanel.add(safetyDistancePanel); |
| | | settingsPanel.add(Box.createRigidArea(new Dimension(0, 25))); |
| | | |
| | | stepPanel.add(settingsPanel); |
| | |
| | | Dikuai dikuai = getOrCreatePendingDikuai(); |
| | | if (dikuai != null) { |
| | | dikuai.setBoundaryOriginalCoordinates(snapshot.originalBoundary); |
| | | dikuai.setBoundaryOriginalXY(snapshot.originalBoundaryXY); |
| | | dikuai.setBoundaryCoordinates(snapshot.optimizedBoundary); |
| | | dikuai.setLandArea(snapshot.areaSqMeters); |
| | | dikuai.setBaseStationCoordinates(snapshot.baseStationCoordinates); |
| | |
| | | } |
| | | |
| | | dikuaiData.put("boundaryOriginalCoordinates", snapshot.originalBoundary); |
| | | dikuaiData.put("boundaryOriginalXY", snapshot.originalBoundaryXY); |
| | | dikuaiData.put("boundaryCoordinates", snapshot.optimizedBoundary); |
| | | dikuaiData.put("landArea", snapshot.areaSqMeters); |
| | | dikuaiData.put("baseStationCoordinates", snapshot.baseStationCoordinates); |
| | | if (activeSession != null) { |
| | | activeSession.data.put("boundaryOriginalCoordinates", snapshot.originalBoundary); |
| | | activeSession.data.put("boundaryOriginalXY", snapshot.originalBoundaryXY); |
| | | activeSession.data.put("boundaryCoordinates", snapshot.optimizedBoundary); |
| | | activeSession.data.put("landArea", snapshot.areaSqMeters); |
| | | activeSession.data.put("baseStationCoordinates", snapshot.baseStationCoordinates); |
| | |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 构建原始边界XY坐标字符串(相对于基准站的XY坐标) |
| | | */ |
| | | private static String buildOriginalBoundaryXYString(List<Coordinate> coordinates, String baseStationCoordinates) { |
| | | if (coordinates == null || coordinates.isEmpty()) { |
| | | return "-1"; |
| | | } |
| | | if (baseStationCoordinates == null || baseStationCoordinates.trim().isEmpty() || "-1".equals(baseStationCoordinates.trim())) { |
| | | return "-1"; |
| | | } |
| | | |
| | | try { |
| | | // 解析基准站坐标 |
| | | String[] baseParts = baseStationCoordinates.split(","); |
| | | if (baseParts.length < 4) { |
| | | return "-1"; |
| | | } |
| | | double baseLat = publicway.Gpstoxuzuobiao.parseDMToDecimal(baseParts[0], baseParts[1]); |
| | | double baseLon = publicway.Gpstoxuzuobiao.parseDMToDecimal(baseParts[2], baseParts[3]); |
| | | |
| | | StringBuilder sb = new StringBuilder(); |
| | | DecimalFormat xyFormat = new DecimalFormat("0.00"); |
| | | for (Coordinate coord : coordinates) { |
| | | double lat = convertToDecimalDegree(coord.getLatitude(), coord.getLatDirection()); |
| | | double lon = convertToDecimalDegree(coord.getLongitude(), coord.getLonDirection()); |
| | | |
| | | // 转换为XY坐标 |
| | | double[] xy = publicway.Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon); |
| | | |
| | | if (sb.length() > 0) { |
| | | sb.append(";"); |
| | | } |
| | | sb.append(xyFormat.format(xy[0])).append(",").append(xyFormat.format(xy[1])); |
| | | } |
| | | return sb.toString(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return "-1"; |
| | | } |
| | | } |
| | | |
| | | private static double convertToDecimalDegree(String dmm, String direction) { |
| | | if (dmm == null || dmm.isEmpty()) { |
| | |
| | | } |
| | | |
| | | String originalBoundary = buildOriginalBoundaryString(uniqueCoordinates); |
| | | String originalBoundaryXY = buildOriginalBoundaryXYString(uniqueCoordinates, baseStationCoordinates); |
| | | DecimalFormat areaFormat = new DecimalFormat("0.00"); |
| | | String areaString = areaFormat.format(area); |
| | | |
| | | return BoundarySnapshotResult.success(originalBoundary, optimizedBoundary, areaString, baseStationCoordinates); |
| | | return BoundarySnapshotResult.success(originalBoundary, originalBoundaryXY, optimizedBoundary, areaString, baseStationCoordinates); |
| | | } |
| | | |
| | | private String resolvePlannerMode(String patternDisplay) { |
| | |
| | | BoundarySnapshotResult snapshot = computeBoundarySnapshot(); |
| | | if (snapshot.success && activeSession != null) { |
| | | activeSession.data.put("boundaryOriginalCoordinates", snapshot.originalBoundary); |
| | | activeSession.data.put("boundaryOriginalXY", snapshot.originalBoundaryXY); |
| | | activeSession.data.put("boundaryCoordinates", snapshot.optimizedBoundary); |
| | | activeSession.data.put("landArea", snapshot.areaSqMeters); |
| | | activeSession.data.put("baseStationCoordinates", snapshot.baseStationCoordinates); |
| | |
| | | if (dikuaiData.containsKey("boundaryOriginalCoordinates")) { |
| | | dikuai.setBoundaryOriginalCoordinates(dikuaiData.get("boundaryOriginalCoordinates")); |
| | | } |
| | | if (dikuaiData.containsKey("boundaryOriginalXY")) { |
| | | dikuai.setBoundaryOriginalXY(dikuaiData.get("boundaryOriginalXY")); |
| | | } |
| | | if (dikuaiData.containsKey("boundaryCoordinates")) { |
| | | dikuai.setBoundaryCoordinates(dikuaiData.get("boundaryCoordinates")); |
| | | } |
| | |
| | | if (isMeaningfulValue(plannedPath)) { |
| | | dikuai.setPlannedPath(plannedPath); |
| | | } |
| | | |
| | | // 保存割草安全距离(优先从dikuaiData获取,否则从TextField获取) |
| | | if (dikuaiData.containsKey("mowingSafetyDistance")) { |
| | | dikuai.setMowingSafetyDistance(dikuaiData.get("mowingSafetyDistance")); |
| | | } else if (mowingSafetyDistanceField != null) { |
| | | String safetyDistanceText = mowingSafetyDistanceField.getText().trim(); |
| | | if (!safetyDistanceText.isEmpty()) { |
| | | try { |
| | | double safetyDistanceMeters = Double.parseDouble(safetyDistanceText); |
| | | dikuai.setMowingSafetyDistance(String.format(Locale.US, "%.2f", safetyDistanceMeters)); |
| | | } catch (NumberFormatException e) { |
| | | dikuai.setMowingSafetyDistance(safetyDistanceText); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Dikuai.putDikuai(landNumber, dikuai); |
| | | Dikuai.saveToProperties(); |