pnpoly算法的原理简述:就是过一个点引一条射线,如果射线与多边形相交的点是奇数,则点在多边形中;如果是偶数,则点在多边形外。
pnpoly算法的详细解析和数学公式可以在网络上查阅,这里不做赘述。为了方便java用户使用,自己实现了一个 java的版本,如果大家有需要用到可以参考一下。
/**
* <p>
* Principle of pnpoly algorithm: draw a ray from a target point,
* and count the number of intersections between this ray and the pair of deformations.
* If there are an odd number of intersections, the target point is inside the polygon,
* and if there are even intersections, it is outside
* </p>
*
* @param vertX polygon coordinates latitudes
* @param vertY polygon coordinates longitudes
* @param x longitude
* @param y latitude
* @return true indicate inside of the polygon, false indicate outside of the polygon
*/
private static boolean pnpolyAlgorithm(List<Double> vertX, List<Double> vertY, double x, double y) {
if (CollectionUtils.isEmpty(vertX) || CollectionUtils.isEmpty(vertY)) {
return false;
}
double maxX = vertX.stream().max(Comparator.comparingDouble(Double::doubleValue)).get();
double maxY = vertY.stream().max(Comparator.comparingDouble(Double::doubleValue)).get();
double minX = vertX.stream().min(Comparator.comparingDouble(Double::doubleValue)).get();
double minY = vertY.stream().min(Comparator.comparingDouble(Double::doubleValue)).get();
if (x < minX || x > maxX || y < minY || y > maxY) {
return false;
}
int i, j;
boolean result = false;
int n = vertX.size();
Double[] vertx = vertX.toArray(new Double[0]);
Double[] verty = vertY.toArray(new Double[0]);
for (i = 0, j = n - 1; i < n; j = i++) {
if ((verty[i] > y) != (verty[j] > y) &&
(x < (vertx[j] - vertx[i]) * (y - verty[i]) / (verty[j] - verty[i]) + vertx[i])) {
result = !result;
}
}
return result;
}
- if (x < minX || x > maxX || y < minY || y > maxY) :简单判断点是否在多边形内;
- 后面循环判断点引出的射线和两点连线相交,如果相交就取反: 偶数结果就是初始值不变(false),奇数就是false取反(true)。
为了方便大家测试,提供一些测试数据:
1.多边形坐标点数据
lat(41.93280493857098).lng(-88.07128206152345) lat(41.9011265125114).lng(-87.9531790341797) lat(41.81572092968781).lng(-88.08707490820314)lat(41.89141546009437).lng(-87.98957124609376)
2. 测试点的数据
- 处于内部点的坐标:
-88.00033330966825, 41.905377402302896-87.99655675937528, 41.905377402302896
- 处于外部点的坐标:
-87.83914710023897, 41.93896430313074-88.02642583896512, 41.881354232950315