826220679@qq.com
17 小时以前 f94b1436d7a28c8e28d010b2cb657ab7c064e353
src/dikuai/daohangyulan.java
@@ -9,8 +9,8 @@
import java.util.ArrayList;
import zhuye.Shouye;
import zhuye.MapRenderer;
import gecaoji.Device;
import gecaoji.Gecaoji;
import gecaoji.Device;
import gecaoji.lujingdraw;
import publicway.buttonset;
@@ -90,73 +90,9 @@
            return;
        }
        // 2. 尝试重新生成完整路径段(包含围边和作业路径)
        // 这样可以确保导航预览时,割草机先沿着内缩边界走一圈,再走割草路径
        List<lujing.Lunjingguihua.PathSegment> segments = null;
        String boundaryCoords = dikuai.getBoundaryCoordinates();
        String mowingWidth = dikuai.getMowingBladeWidth(); // 注意:这里应该用割草宽度,而不是割刀宽度,通常是一样的
        // 如果没有割草宽度,尝试从Device获取
        if (mowingWidth == null || mowingWidth.trim().isEmpty() || "-1".equals(mowingWidth.trim())) {
             Device device = Device.getActiveDevice();
             if (device != null) {
                 mowingWidth = device.getMowingWidth();
             }
        }
        // 如果还是没有,使用默认值
        if (mowingWidth == null || mowingWidth.trim().isEmpty() || "-1".equals(mowingWidth.trim())) {
            mowingWidth = "0.34";
        }
        String safetyDistance = dikuai.getMowingSafetyDistance();
        String obstaclesCoords = dikuai.getObstacleCoordinates();
        String mowingPattern = dikuai.getMowingPattern();
        if (boundaryCoords != null && !boundaryCoords.trim().isEmpty() && !"-1".equals(boundaryCoords.trim())) {
            try {
                // 解析割草模式
                String mode = "parallel"; // 默认平行模式
                if (mowingPattern != null && !mowingPattern.trim().isEmpty()) {
                    String pattern = mowingPattern.trim().toLowerCase();
                    if ("1".equals(pattern) || "spiral".equals(pattern) || "螺旋式".equals(pattern) || "螺旋".equals(pattern)) {
                        mode = "spiral";
                    } else if ("parallel".equals(pattern) || "平行线".equals(pattern) || "平行".equals(pattern)) {
                        mode = "parallel";
                    }
                }
                // 调用路径规划生成完整路径段
                segments = lujing.Lunjingguihua.generatePathSegments(
                    boundaryCoords,
                    obstaclesCoords != null ? obstaclesCoords : "",
                    mowingWidth,
                    safetyDistance,
                    mode
                );
            } catch (Exception e) {
                // 如果重新生成失败,segments 为 null
                System.err.println("导航预览重新生成路径失败: " + e.getMessage());
            }
        }
        // 3. 构建最终导航路径点列表
        pathPoints = new ArrayList<>();
        if (segments != null && !segments.isEmpty()) {
            // 如果成功生成了路径段,使用路径段构建点列表
            // 这样包含了围边路径和作业路径,以及它们之间的连接
            lujing.Lunjingguihua.PathSegment firstSeg = segments.get(0);
            pathPoints.add(new Point2D.Double(firstSeg.start.x, firstSeg.start.y));
            for (lujing.Lunjingguihua.PathSegment seg : segments) {
                // 添加终点(起点已经在上一次循环或初始化时添加了)
                // 注意:这里假设路径段是连续的,或者我们只关心端点
                // 如果段之间不连续(有空走),generatePathSegments 应该已经生成了连接段(isMowing=false)
                pathPoints.add(new Point2D.Double(seg.end.x, seg.end.y));
            }
        } else {
            // 如果生成失败,回退到使用原始解析的路径点
            // 这通常只包含作业路径,可能没有围边
            pathPoints = rawPathPoints;
        }
        // 直接使用解析出来的路径点
        pathPoints = rawPathPoints;
        
        if (pathPoints == null || pathPoints.size() < 2) {
             JOptionPane.showMessageDialog(null, "无法构建有效的导航路径", "错误", JOptionPane.ERROR_MESSAGE);
@@ -166,6 +102,11 @@
        this.currentDikuai = dikuai;
        this.currentPathIndex = 0;
        this.currentSpeed = DEFAULT_SPEED;
        // 将当前速度(米/秒)转换为km/h写入设备yaw属性
        try {
            double kmh = this.currentSpeed * 3.6;
            Device.getActiveDevice().setYaw(String.valueOf(kmh));
        } catch (Exception ignore) { }
        this.navigationTrack.clear();
        
        // 获取首页和地图渲染器
@@ -514,9 +455,9 @@
    
    /**
     * 计算两点之间的方向角(度)
     * 图标默认朝上,向右旋转90度车头朝右
     * atan2返回的角度:向右是0度,向上是90度
     * 需要转换为图标旋转角度:向右需要90度,向上需要0度
     * 车辆图标的车头默认是在屏幕正下方(270度)
     * atan2返回的角度:向右是0度,向上是90度,向左是180度,向下是-90度(270度)
     * 需要转换为图标旋转角度,使车头朝向行驶方向
     */
    private double calculateHeading(Point2D.Double from, Point2D.Double to) {
        double dx = to.x - from.x;
@@ -529,13 +470,13 @@
            atan2Angle += 360;
        }
        
        // 图标默认朝上(0度),向右旋转90度车头朝右
        // 所以:运动方向向右(0度)→ 需要旋转90度
        //      运动方向向上(90度)→ 需要旋转0度
        //      运动方向向左(180度)→ 需要旋转270度
        //      运动方向向下(270度)→ 需要旋转180度
        // 公式:heading = (90 - atan2Angle + 360) % 360
        double heading = (90.0 - atan2Angle + 360.0) % 360.0;
        // 图标默认朝下(270度),需要计算旋转角度使车头朝向行驶方向
        // 如果运动方向向上(90度)→ 需要旋转180度(270 - 90 = 180)
        // 如果运动方向向右(0度)→ 需要旋转270度(270 - 0 = 270)
        // 如果运动方向向左(180度)→ 需要旋转90度(270 - 180 = 90)
        // 如果运动方向向下(270度)→ 需要旋转0度(270 - 270 = 0)
        // 公式:heading = (270 - atan2Angle + 360) % 360
        double heading = (270.0 - atan2Angle + 360.0) % 360.0;
        
        return heading;
    }
@@ -554,6 +495,11 @@
     */
    private void speedUp() {
        currentSpeed += SPEED_MULTIPLIER;
        // 同步到设备yaw属性(km/h)
        try {
            double kmh = currentSpeed * 3.6;
            Device.getActiveDevice().setYaw(String.valueOf(kmh));
        } catch (Exception ignore) { }
        updateSpeedDisplay();
    }
    
@@ -567,6 +513,11 @@
                currentSpeed = 0.1;
            }
        }
        // 同步到设备yaw属性(km/h)
        try {
            double kmh = currentSpeed * 3.6;
            Device.getActiveDevice().setYaw(String.valueOf(kmh));
        } catch (Exception ignore) { }
        updateSpeedDisplay();
    }
    
@@ -574,8 +525,11 @@
     * 更新速度显示
     */
    private void updateSpeedDisplay() {
        // 可以在地图上显示当前速度
        // 这里暂时不实现,如果需要可以在MapRenderer中添加速度显示
        // 导航预览下在割草机图标上方实时显示速度(固定像素间距)
        if (mapRenderer != null) {
            mapRenderer.setNavigationPreviewSpeed(currentSpeed);
            mapRenderer.repaint();
        }
    }
    
    /**
@@ -607,6 +561,11 @@
            mapRenderer.setNavigationPreviewSpeed(0.0); // 清除速度显示
            mapRenderer.repaint();
        }
        // 退出时将设备yaw属性重置为0
        try {
            Device.getActiveDevice().setYaw("0");
        } catch (Exception ignore) { }
        
        // 恢复地块管理页面
        // 在清空currentDikuai之前保存地块编号,使用final变量以便在lambda中使用