在开发中我们经常会遇到需要监听手势动作的需求,往往这些需求会与界面的某个区域绑定。但是当该区域是一个不规则的多边形时,这就给我们的判断添加了相当大的难度。
其实在百度地图中就有判断点是否在指定区域内的功能,API中提供了相关的方法。但我们不可能在不使用地图功能的时候去特地导入BaiDuMap来实现这一功能,所以在这里我将改功能的实现提取出自定义一个工具类。
首先定义一个类Point,表示点
public class Point {
double x;//X坐标
double y;//y坐标
}
之后就是重头戏
/**
* 参照百度地图的SpatialRelationUtil工具类
*/
public class SpatialRelationUtil {
private SpatialRelationUtil() {
}
/**
* 返回一个点是否在一个多边形区域内
*
* @param mPoints 多边形坐标点列表
* @param point 待判断点
* @return true 多边形包含这个点,false 多边形未包含这个点。
*/
public static boolean isPolygonContainsPoint(List<Point> mPoints, Point point) {
int nCross = 0;
for (int i = 0; i < mPoints.size(); i++) {
Point p1 = mPoints.get(i);
Point p2 = mPoints.get((i + 1) % mPoints.size());
// 取多边形任意一个边,做点point的水平延长线,求解与当前边的交点个数
// p1p2是水平线段,要么没有交点,要么有无限个交点
if (p1.getY() == p2.getY())
continue;
// point 在p1p2 底部 --> 无交点
if (point.getY() < Math.min(p1.getY(), p2.getY()))
continue;
// point 在p1p2 顶部 --> 无交点
if (point.getY() >= Math.max(p1.getY(), p2.getY()))
continue;
// 求解 point点水平线与当前p1p2边的交点的 X 坐标
double x = (point.getY() - p1.getY()) * (p2.getX() - p1.getX()) / (p2.getY() - p1.getY()) + p1.getX();
if (x > point.getX()) // 当x=point.x时,说明point在p1p2线段上
nCross++; // 只统计单边交点
}
// 单边交点为偶数,点在多边形之外 ---
return (nCross % 2 == 1);
}
/**
* 返回一个点是否在一个多边形边界上
*
* @param mPoints 多边形坐标点列表
* @param point 待判断点
* @return true 点在多边形边上,false 点不在多边形边上。
*/
public static boolean isPointInPolygonBoundary(List<Point> mPoints, Point point) {
for (int i = 0; i < mPoints.size(); i++) {
Point p1 = mPoints.get(i);
Point p2 = mPoints.get((i + 1) % mPoints.size());
// 取多边形任意一个边,做点point的水平延长线,求解与当前边的交点个数
// point 在p1p2 底部 --> 无交点
if (point.getY() < Math.min(p1.getY(), p2.getY()))
continue;
// point 在p1p2 顶部 --> 无交点
if (point.getY() > Math.max(p1.getY(), p2.getY()))
continue;
// p1p2是水平线段,要么没有交点,要么有无限个交点
if (p1.getY() == p2.getY()) {
double minX = Math.min(p1.getX(), p2.getX());
double maxX = Math.max(p1.getX(), p2.getX());
// point在水平线段p1p2上,直接return true
if ((point.getY() == p1.getY()) && (point.getX() >= minX && point.getX() <= maxX)) {
return true;
}
} else { // 求解交点
double x = (point.getY() - p1.getY()) * (p2.getX() - p1.getX()) / (p2.getY() - p1.getY()) + p1.getX();
if (x == point.getX()) // 当x=point.x时,说明point在p1p2线段上
return true;
}
}
return false;
}
}
我们可以直接通过静态方法
isPolygonContainsPoint 来判断点是否在区域内;
参数List<Point> mPoints 表示区域边界组成的点的列表,必须沿边界顺序添加
而第二个参数就明显表示所需要判断的点的坐标