/**
* 判断该点是否在区域内
* 说明:该点出发的射线模拟为向左射出的水平射线
* @param pointList 电子围栏的坐标点集合
* @param point 坐标点
* @return
*/
public static Boolean isInArea(List<Point2D.Double> pointList, Point2D.Double point) {
Point2D.Double p1, p2;
Integer across = 0; //穿越次数
double precision = 2e-10; //浮点类型计算时候的比较容差
for (int i = 0; i < pointList.size(); i++) {
p1 = pointList.get(i);
//下一个点 如果是最后一个点 则是第一个点的坐标
p2 = pointList.get((i + 1) >= pointList.size() ? 0 : (i + 1));
// 1、在点上返回true
if (p1.equals(point) || p2.equals(point)) {
return true;
}
// 2、判断维度在范围内
if (point.y <= Math.max(p1.y, p2.y) && point.y >= Math.min(p1.y, p2.y)) {
// 3、判断精度在范围内(并且 压线)
if (point.x <= Math.max(p1.x, p2.x) && point.x >= Math.min(p1.x, p2.x)) {
// 其一:水平线 压线
if (p1.y == p2.y&&point.y == p1.y) {
return true;
}
// 其二:垂直线 压线
if (p1.x == p2.x&&point.x == p1.x) {
return true;
}
// 其三:压斜线
double xianShangY = p1.y + (point.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x);
if (Math.abs(xianShangY - point.y) < precision) {
// 在线上
return true;
}
}
// 4、精度压线 或在范围外
if (point.x <= Math.min(p1.x, p2.x)) {
continue;
}
/*
该点位于两个端点之间,判断是否穿过顶点(穿过顶点时,顶点按照在射线上部处理)
穿过顶点时,只有两个端点在射线两侧的才按照穿越处理
*/
if (p1.y != p2.y && point.y != Math.min(p1.y, p2.y)) {
across++;
}
}
}
if (across % 2 == 0) {
// 偶数,在外部
return false;
}
return true;
}
判断依据是 坐标点 任意延伸一条线 如果穿插0 偶数条线 则在坐标以外 奇数条线则在坐标以内
只支持二维区域 (不要画这种莫比乌斯环克莱因瓶这样的奇奇怪怪的圈)