张世豪
2025-12-12 3e3bd3a148990fb485323b67b9c0edb5bfb4b5e5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package gecaoji;
 
import java.awt.geom.Point2D;
import java.util.List;
 
/**
 * 割草机边界检查工具类。
 *
 * 用法契约:
 * - 输入的地块边界为闭合的多边形点序列(顺序为顺时针或逆时针均可),每个点包含 X(米)、Y(米)坐标。
 * - 若点位于多边形内部或位于边界线上,返回 true;否则返回 false。
 */
public final class MowerBoundaryChecker {
 
    private MowerBoundaryChecker() { }
 
    /**
     * 判断给定点是否在边界多边形内部(含边界)。
     *
     * @param polygonPoints 边界点列表,每个元素为 double[2],索引0为x,索引1为y;至少需要3个点
     * @param x 割草机实时X坐标(米)
     * @param y 割草机实时Y坐标(米)
     * @return 如果点在多边形内部或边界上则返回 true;否则返回 false
     */
    public static boolean isInsideBoundary(List<double[]> polygonPoints, double x, double y) {
        if (polygonPoints == null || polygonPoints.size() < 3) {
            return false;
        }
        int n = polygonPoints.size();
        boolean inside = false;
        for (int i = 0, j = n - 1; i < n; j = i++) {
            double xi = polygonPoints.get(i)[0];
            double yi = polygonPoints.get(i)[1];
            double xj = polygonPoints.get(j)[0];
            double yj = polygonPoints.get(j)[1];
 
            // 判断点是否在当前边上(考虑浮点容差)
            if (pointOnSegment(xj, yj, xi, yi, x, y)) {
                return true;
            }
 
            boolean intersect = ((yi > y) != (yj > y)) &&
                    (x < (xj - xi) * (y - yi) / (yj - yi + 0.0) + xi);
            if (intersect) {
                inside = !inside;
            }
        }
        return inside;
    }
 
    /**
     * 重载:接受 Point2D 列表
     */
    public static boolean isInsideBoundaryPoints(List<Point2D.Double> polygonPoints, double x, double y) {
        if (polygonPoints == null || polygonPoints.size() < 3) {
            return false;
        }
        int n = polygonPoints.size();
        boolean inside = false;
        for (int i = 0, j = n - 1; i < n; j = i++) {
            double xi = polygonPoints.get(i).x;
            double yi = polygonPoints.get(i).y;
            double xj = polygonPoints.get(j).x;
            double yj = polygonPoints.get(j).y;
 
            if (pointOnSegment(xj, yj, xi, yi, x, y)) {
                return true;
            }
 
            boolean intersect = ((yi > y) != (yj > y)) &&
                    (x < (xj - xi) * (y - yi) / (yj - yi + 0.0) + xi);
            if (intersect) {
                inside = !inside;
            }
        }
        return inside;
    }
 
    /**
     * 重载:接受二维数组 double[][],每行 [x,y]
     */
    public static boolean isInsideBoundary(double[][] polygon, double x, double y) {
        if (polygon == null || polygon.length < 3) {
            return false;
        }
        int n = polygon.length;
        boolean inside = false;
        for (int i = 0, j = n - 1; i < n; j = i++) {
            double xi = polygon[i][0];
            double yi = polygon[i][1];
            double xj = polygon[j][0];
            double yj = polygon[j][1];
 
            if (pointOnSegment(xj, yj, xi, yi, x, y)) {
                return true;
            }
 
            boolean intersect = ((yi > y) != (yj > y)) &&
                    (x < (xj - xi) * (y - yi) / (yj - yi + 0.0) + xi);
            if (intersect) {
                inside = !inside;
            }
        }
        return inside;
    }
 
    // 判断点是否在线段 (x1,y1)-(x2,y2) 上(包括端点),允许小的数值误差
    private static boolean pointOnSegment(double x1, double y1, double x2, double y2, double px, double py) {
        double cross = (px - x1) * (y2 - y1) - (py - y1) * (x2 - x1);
        double eps = 1e-8;
        if (Math.abs(cross) > eps) {
            return false;
        }
        double dot = (px - x1) * (px - x2) + (py - y1) * (py - y2);
        return dot <= eps;
    }
}