| | |
| | | contentPanel.add(createTextAreaSection(obstacleTitle, obstacleArea)); |
| | | |
| | | // 割草宽度 |
| | | widthField = createInfoTextField(widthValue != null ? widthValue : "", true); |
| | | contentPanel.add(createTextFieldSection("割草宽度 (cm)", widthField)); |
| | | String displayWidth = ""; |
| | | if (widthValue != null && !widthValue.trim().isEmpty() && !"-1".equals(widthValue.trim())) { |
| | | try { |
| | | double val = Double.parseDouble(widthValue.trim()); |
| | | // 简单的启发式转换:如果值大于5,假设是厘米,转换为米 |
| | | if (val > 5) { |
| | | val = val / 100.0; |
| | | } |
| | | displayWidth = String.format(Locale.US, "%.2f", val); |
| | | } catch (NumberFormatException e) { |
| | | displayWidth = widthValue; |
| | | } |
| | | } |
| | | widthField = createInfoTextField(displayWidth, true); |
| | | contentPanel.add(createTextFieldSection("割草宽度 (m)", widthField)); |
| | | |
| | | // 割草安全距离(只读显示) |
| | | // 优先从Dikuai对象获取,如果Dikuai中没有,再从Device获取 |
| | |
| | | String sanitizedWidth = sanitizeWidthString(widthField.getText()); |
| | | if (sanitizedWidth != null) { |
| | | try { |
| | | double widthCm = Double.parseDouble(sanitizedWidth); |
| | | widthField.setText(formatWidthForStorage(widthCm)); |
| | | sanitizedWidth = formatWidthForStorage(widthCm); |
| | | double widthMeters = Double.parseDouble(sanitizedWidth); |
| | | widthField.setText(formatWidthForStorage(widthMeters)); |
| | | sanitizedWidth = formatWidthForStorage(widthMeters); |
| | | } catch (NumberFormatException ex) { |
| | | widthField.setText(sanitizedWidth); |
| | | } |
| | |
| | | String rawWidthInput = widthField.getText() != null ? widthField.getText().trim() : ""; |
| | | String widthSanitized = sanitizeWidthString(widthField.getText()); |
| | | if (widthSanitized == null) { |
| | | String message = rawWidthInput.isEmpty() ? "请先设置割草宽度(cm)" : "割草宽度格式不正确"; |
| | | String message = rawWidthInput.isEmpty() ? "请先设置割草宽度(m)" : "割草宽度格式不正确"; |
| | | JOptionPane.showMessageDialog(this, message, "提示", JOptionPane.WARNING_MESSAGE); |
| | | return; |
| | | } |
| | | |
| | | double widthCm; |
| | | double widthMeters; |
| | | try { |
| | | widthCm = Double.parseDouble(widthSanitized); |
| | | widthMeters = Double.parseDouble(widthSanitized); |
| | | } catch (NumberFormatException ex) { |
| | | JOptionPane.showMessageDialog(this, "割草宽度格式不正确", "提示", JOptionPane.WARNING_MESSAGE); |
| | | return; |
| | | } |
| | | |
| | | if (widthCm <= 0) { |
| | | if (widthMeters <= 0) { |
| | | JOptionPane.showMessageDialog(this, "割草宽度必须大于0", "提示", JOptionPane.WARNING_MESSAGE); |
| | | return; |
| | | } |
| | | |
| | | String widthNormalized = formatWidthForStorage(widthCm); |
| | | String widthNormalized = formatWidthForStorage(widthMeters); |
| | | widthField.setText(widthNormalized); |
| | | |
| | | String pathNormalized = normalizeCoordinateInput(pathArea.getText()); |
| | |
| | | String widthStr = sanitizeWidthString(widthCmInput); |
| | | if (widthStr == null) { |
| | | if (showMessages) { |
| | | String message = rawWidth.isEmpty() ? "请先设置割草宽度(cm)" : "割草宽度格式不正确"; |
| | | String message = rawWidth.isEmpty() ? "请先设置割草宽度(m)" : "割草宽度格式不正确"; |
| | | JOptionPane.showMessageDialog(parentComponent, message, "提示", JOptionPane.WARNING_MESSAGE); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | double widthCm; |
| | | double widthVal; |
| | | try { |
| | | widthCm = Double.parseDouble(widthStr); |
| | | widthVal = Double.parseDouble(widthStr); |
| | | } catch (NumberFormatException ex) { |
| | | if (showMessages) { |
| | | JOptionPane.showMessageDialog(parentComponent, "割草宽度格式不正确", |
| | |
| | | return null; |
| | | } |
| | | |
| | | if (widthCm <= 0) { |
| | | if (widthVal <= 0) { |
| | | if (showMessages) { |
| | | JOptionPane.showMessageDialog(parentComponent, "割草宽度必须大于0", |
| | | "提示", JOptionPane.WARNING_MESSAGE); |
| | |
| | | return null; |
| | | } |
| | | |
| | | double widthMeters = widthCm / 100.0d; |
| | | double widthMeters = widthVal; |
| | | String plannerWidth = BigDecimal.valueOf(widthMeters) |
| | | .setScale(3, RoundingMode.HALF_UP) |
| | | .stripTrailingZeros() |
| | |
| | | // 无障碍物的情况 |
| | | if (grassType == 1) { |
| | | // 凸形地块,无障碍物 -> 调用 AoxinglujingNoObstacle |
| | | System.out.println("调用算法: 凸形无障碍物, 类名: AoxinglujingNoObstacle"); |
| | | List<AoxinglujingNoObstacle.PathSegment> segments = |
| | | AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr); |
| | | generated = formatAoxingPathSegments(segments); |
| | | } else if (grassType == 2) { |
| | | // 异形地块,无障碍物 -> 调用 YixinglujingNoObstacle |
| | | // 调用 YixinglujingNoObstacle.planPath 获取路径段列表 |
| | | System.out.println("调用算法: 异形无障碍物, 类名: YixinglujingNoObstacle"); |
| | | List<YixinglujingNoObstacle.PathSegment> segments = |
| | | YixinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr); |
| | | // 格式化路径段列表为字符串 |
| | |
| | | JOptionPane.showMessageDialog(parentComponent, "无法判断地块类型,尝试按凸形地块处理", |
| | | "提示", JOptionPane.WARNING_MESSAGE); |
| | | } |
| | | System.out.println("调用算法: 无法判断类型(默认凸形无障碍物), 类名: AoxinglujingNoObstacle"); |
| | | List<AoxinglujingNoObstacle.PathSegment> segments = |
| | | AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr); |
| | | generated = formatAoxingPathSegments(segments); |
| | |
| | | if (grassType == 1) { |
| | | // 凸形地块,有障碍物 -> 调用 AoxinglujingHaveObstacel |
| | | // 传入参数:boundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D) |
| | | System.out.println("调用算法: 凸形有障碍物, 类名: AoxinglujingHaveObstacel"); |
| | | List<AoxinglujingHaveObstacel.PathSegment> segments = |
| | | AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr); |
| | | generated = formatAoxingHaveObstaclePathSegments(segments); |
| | | } else if (grassType == 2) { |
| | | // 异形地块,有障碍物 -> 调用 YixinglujingHaveObstacel |
| | | // 传入参数:boundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D) |
| | | System.out.println("调用算法: 异形有障碍物, 类名: YixinglujingHaveObstacel"); |
| | | List<YixinglujingHaveObstacel.PathSegment> segments = |
| | | YixinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr); |
| | | generated = formatYixingHaveObstaclePathSegments(segments); |
| | |
| | | JOptionPane.showMessageDialog(parentComponent, "无法判断地块类型,尝试按凸形地块处理", |
| | | "提示", JOptionPane.WARNING_MESSAGE); |
| | | } |
| | | System.out.println("调用算法: 无法判断类型(默认凸形有障碍物), 类名: AoxinglujingHaveObstacel"); |
| | | List<AoxinglujingHaveObstacel.PathSegment> segments = |
| | | AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr); |
| | | generated = formatAoxingHaveObstaclePathSegments(segments); |
| | |
| | | return cleaned.isEmpty() ? null : cleaned; |
| | | } |
| | | |
| | | private String formatWidthForStorage(double widthCm) { |
| | | return BigDecimal.valueOf(widthCm) |
| | | .setScale(2, RoundingMode.HALF_UP) |
| | | .stripTrailingZeros() |
| | | .toPlainString(); |
| | | private String formatWidthForStorage(double widthVal) { |
| | | return String.format(Locale.US, "%.2f", widthVal); |
| | | } |
| | | |
| | | private String formatMowingPatternForDialog(String patternValue) { |