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 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 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; } }