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