张世豪
18 小时以前 1175f5fbe8fd832943880bfc37c0e2a451a0688a
src/gecaoji/lujingdraw.java
@@ -1,5 +1,4 @@
package gecaoji; // 包声明
import java.awt.BasicStroke; // 引入基础描边类
import java.awt.Color; // 引入颜色类
import java.awt.Graphics2D; // 引入2D图形上下文
@@ -8,7 +7,6 @@
import java.awt.geom.Point2D; // 引入二维点类
import java.util.ArrayList; // 引入动态数组
import java.util.List; // 引入列表接口
import lujing.Lunjingguihua; // 引入路径规划类
import org.locationtech.jts.geom.Coordinate; // 引入坐标类
import org.locationtech.jts.geom.GeometryFactory; // 引入几何工厂类
import org.locationtech.jts.geom.Polygon; // 引入多边形类
@@ -24,7 +22,7 @@
    // 蓝色 - 用于非作业移动路径
    private static final Color TRAVEL_PATH_COLOR = new Color(0, 0, 255);
    // 虚线样式 - 用于非作业移动路径
    private static final float[] DASH_PATTERN = {10.0f, 5.0f};
    private static final float[] DASH_PATTERN = {5.0f, 5.0f};
    private static final Color START_POINT_COLOR = new Color(0, 0, 0, 220); // 起点箭头颜色
    private static final Color END_POINT_COLOR = new Color(0, 0, 0, 220); // 终点箭头颜色
@@ -107,62 +105,29 @@
            drawInnerBoundary(g2d, boundaryCoords, safetyDistance, scale);
        }
        
        // 2. 尝试重新生成路径段以区分作业路径和移动路径
        List<Lunjingguihua.PathSegment> segments = null;
        if (boundaryCoords != null && mowingWidth != null) {
            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 = Lunjingguihua.generatePathSegments(
                    boundaryCoords,
                    obstaclesCoords != null ? obstaclesCoords : "",
                    mowingWidth,
                    safetyDistance,
                    mode
                );
            } catch (Exception e) {
                // 如果重新生成失败,使用简单绘制方式
                segments = null;
            }
        }
        // 2. 直接绘制路径(不再重新生成)
        Path2D polyline = new Path2D.Double(); // 创建折线
        boolean move = true; // 首段标记
        for (Point2D.Double point : path) { // 遍历点集
            if (move) { // 第一段
                polyline.moveTo(point.x, point.y); // 移动到首点
                move = false; // 更新标记
            } else { // 后续段
                polyline.lineTo(point.x, point.y); // 连线到下一点
            } // if结束
        } // for结束
        
        // 3. 根据是否有段信息选择不同的绘制方式
        if (segments != null && !segments.isEmpty()) {
            // 有段信息:分别绘制作业路径和移动路径
            drawPathSegments(g2d, segments, scale, arrowScale);
        } else {
            // 无段信息:使用简单绘制方式(所有路径使用作业路径颜色)
            Path2D polyline = new Path2D.Double(); // 创建折线
            boolean move = true; // 首段标记
            for (Point2D.Double point : path) { // 遍历点集
                if (move) { // 第一段
                    polyline.moveTo(point.x, point.y); // 移动到首点
                    move = false; // 更新标记
                } else { // 后续段
                    polyline.lineTo(point.x, point.y); // 连线到下一点
                } // if结束
            } // for结束
            g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 设置圆头圆角描边
            g2d.setColor(MOWING_PATH_COLOR); // 设置作业路径颜色(提香红70%透明度)
            g2d.draw(polyline); // 绘制折线
            Point2D.Double start = path.get(0); // 起点
            Point2D.Double second = path.get(1); // 第二个点
            Point2D.Double end = path.get(path.size() - 1); // 终点
            Point2D.Double prev = path.get(path.size() - 2); // 倒数第二个点
        g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 设置圆头圆角描边
        g2d.setColor(MOWING_PATH_COLOR); // 设置作业路径颜色(提香红70%透明度)
        g2d.draw(polyline); // 绘制折线
        Point2D.Double start = path.get(0); // 起点
        Point2D.Double second = path.get(1); // 第二个点
        Point2D.Double end = path.get(path.size() - 1); // 终点
        Point2D.Double prev = path.get(path.size() - 2); // 倒数第二个点
            drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 绘制起点箭头
            drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 绘制终点箭头
        }
        drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 绘制起点箭头
        drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 绘制终点箭头
        g2d.setStroke(previous); // 恢复原描边
    } // 方法结束
@@ -172,7 +137,7 @@
     */ // 文档注释结束
    private static void drawInnerBoundary(Graphics2D g2d, String boundaryCoords, String safetyDistanceStr, double scale) {
        try {
            List<Coordinate> boundary = Lunjingguihua.parseCoordinates(boundaryCoords);
            List<Coordinate> boundary = parseCoordinates(boundaryCoords);
            if (boundary.size() < 4) {
                return; // 边界点不足
            }
@@ -258,89 +223,7 @@
        }
    } // 方法结束
    
    /** // 文档注释开始
     * 绘制路径段(区分作业路径和移动路径)
     */ // 文档注释结束
    private static void drawPathSegments(Graphics2D g2d, List<Lunjingguihua.PathSegment> segments, double scale, double arrowScale) {
        if (segments == null || segments.isEmpty()) {
            return;
        }
        float strokeWidth = (float) (2.5 / Math.max(0.5, scale));
        Stroke previous = g2d.getStroke();
        // 分别绘制作业路径和移动路径
        Path2D.Double mowingPath = new Path2D.Double();
        Path2D.Double travelPath = new Path2D.Double();
        boolean mowingStarted = false;
        boolean travelStarted = false;
        Coordinate lastMowingEnd = null;
        Coordinate lastTravelEnd = null;
        for (Lunjingguihua.PathSegment seg : segments) {
            if (seg == null || seg.start == null || seg.end == null) {
                continue;
            }
            if (seg.isMowing) {
                // 作业路径 - 提香红70%透明度
                if (!mowingStarted || lastMowingEnd == null || !equals2D(lastMowingEnd, seg.start)) {
                    mowingPath.moveTo(seg.start.x, seg.start.y);
                    mowingStarted = true;
                }
                mowingPath.lineTo(seg.end.x, seg.end.y);
                lastMowingEnd = seg.end;
            } else {
                // 移动路径 - 蓝色虚线
                if (!travelStarted || lastTravelEnd == null || !equals2D(lastTravelEnd, seg.start)) {
                    travelPath.moveTo(seg.start.x, seg.start.y);
                    travelStarted = true;
                }
                travelPath.lineTo(seg.end.x, seg.end.y);
                lastTravelEnd = seg.end;
            }
        }
        // 绘制作业路径
        if (mowingStarted) {
            g2d.setColor(MOWING_PATH_COLOR); // 提香红70%透明度
            g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g2d.draw(mowingPath);
        }
        // 绘制移动路径(虚线)
        if (travelStarted) {
            g2d.setColor(TRAVEL_PATH_COLOR); // 蓝色
            g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASH_PATTERN, 0));
            g2d.draw(travelPath);
        }
        // 绘制起点和终点箭头
        if (!segments.isEmpty()) {
            Lunjingguihua.PathSegment firstSeg = segments.get(0);
            if (firstSeg != null && firstSeg.start != null && segments.size() > 1) {
                Lunjingguihua.PathSegment secondSeg = segments.get(1);
                if (secondSeg != null && secondSeg.start != null) {
                    Point2D.Double start = new Point2D.Double(firstSeg.start.x, firstSeg.start.y);
                    Point2D.Double second = new Point2D.Double(secondSeg.start.x, secondSeg.start.y);
                    drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale);
                }
            }
            Lunjingguihua.PathSegment lastSeg = segments.get(segments.size() - 1);
            if (lastSeg != null && lastSeg.end != null && segments.size() > 1) {
                Lunjingguihua.PathSegment prevSeg = segments.get(segments.size() - 2);
                if (prevSeg != null && prevSeg.end != null) {
                    Point2D.Double prev = new Point2D.Double(prevSeg.end.x, prevSeg.end.y);
                    Point2D.Double end = new Point2D.Double(lastSeg.end.x, lastSeg.end.y);
                    drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale);
                }
            }
        }
        g2d.setStroke(previous);
    } // 方法结束
    
    /** // 文档注释开始
     * 比较两个坐标是否相同(容差)
@@ -392,4 +275,36 @@
        g2d.setColor(color); // 设置颜色
        g2d.fill(arrow); // 填充箭头
    } // 方法结束
    /**
     * 解析坐标字符串
     */
    private static List<Coordinate> parseCoordinates(String s) {
        List<Coordinate> list = new ArrayList<>();
        if (s == null || s.trim().isEmpty()) return list;
        // 增强正则:处理可能存在的多种分隔符
        String[] pts = s.split("[;\\s]+");
        for (String p : pts) {
            String trimmed = p.trim().replace("(", "").replace(")", "");
            if (trimmed.isEmpty()) continue;
            String[] xy = trimmed.split("[,,\\s]+");
            if (xy.length >= 2) {
                try {
                    double x = Double.parseDouble(xy[0].trim());
                    double y = Double.parseDouble(xy[1].trim());
                    // 过滤无效坐标
                    if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) {
                        list.add(new Coordinate(x, y));
                    }
                } catch (NumberFormatException ex) {
                    // 忽略解析错误的点
                }
            }
        }
        // 确保多边形闭合
        if (list.size() > 2 && !list.get(0).equals2D(list.get(list.size() - 1))) {
            list.add(new Coordinate(list.get(0)));
        }
        return list;
    }
} // 类结束