如何在Java 11中判断com.mapbox.geojson.Point是否在Polygon内?
判断Mapbox GeoJSON Point是否在Polygon内的Java 11实现
嘿,我刚好之前处理过类似的需求,用Java 11判断Mapbox的Point是否在Polygon范围内其实可以通过实现经典的射线法来搞定——毕竟Mapbox的GeoJSON库本身好像没直接提供这个判断方法。下面给你具体的实现步骤和可直接复用的代码:
核心逻辑:射线法(Ray Casting Algorithm)
射线法的原理很简单:从目标点向右发射一条水平射线,统计这条射线与多边形边的交点数量。如果交点数是奇数,说明点在多边形内部;如果是偶数,则在外部。同时我们额外处理了点刚好在多边形边上的情况,直接返回true。
完整工具类代码
首先导入需要的Mapbox GeoJSON类,然后实现工具类:
import com.mapbox.geojson.Point; import com.mapbox.geojson.Polygon; import com.mapbox.geojson.Position; import java.util.List; public class GeoUtils { // 判断点是否在多边形内(包含边界) public static boolean isPointInPolygon(Point point, Polygon polygon) { Position pointPos = point.coordinates(); double pointX = pointPos.longitude(); double pointY = pointPos.latitude(); // 获取多边形的外环坐标(第一个List是外环,后续List是内环/洞) List<Position> outerRing = polygon.coordinates().get(0); int vertexCount = outerRing.size(); boolean inside = false; // 遍历多边形的每条边(j是i的前一个顶点,形成边j->i) for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++) { Position posI = outerRing.get(i); Position posJ = outerRing.get(j); double xi = posI.longitude(), yi = posI.latitude(); double xj = posJ.longitude(), yj = posJ.latitude(); // 先判断点是否在当前边上,是则直接返回true if (isPointOnLineSegment(pointX, pointY, xi, yi, xj, yj)) { return true; } // 核心判断:射线与当前边是否相交 boolean intersects = ((yi > pointY) != (yj > pointY)) && (pointX < (xj - xi) * (pointY - yi) / (yj - yi) + xi); if (intersects) { inside = !inside; } } // 如果有内环(洞),需要额外判断点是否不在任何内环内 for (int k = 1; k < polygon.coordinates().size(); k++) { List<Position> innerRing = polygon.coordinates().get(k); if (isPointInRing(pointX, pointY, innerRing)) { return false; // 点在洞里,返回不在多边形内 } } return inside; } // 判断点是否在单条环(外环/内环)内(无边界判断,用于内环检测) private static boolean isPointInRing(double px, double py, List<Position> ring) { int vertexCount = ring.size(); boolean inside = false; for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++) { Position posI = ring.get(i); Position posJ = ring.get(j); double xi = posI.longitude(), yi = posI.latitude(); double xj = posJ.longitude(), yj = posJ.latitude(); boolean intersects = ((yi > py) != (yj > py)) && (px < (xj - xi) * (py - yi) / (yj - yi) + xi); if (intersects) { inside = !inside; } } return inside; } // 判断点是否在线段上(处理边界情况) private static boolean isPointOnLineSegment(double px, double py, double x1, double y1, double x2, double y2) { // 先判断点是否在线段的包围盒内 boolean withinXBounds = Math.min(x1, x2) - 1e-8 <= px && px <= Math.max(x1, x2) + 1e-8; boolean withinYBounds = Math.min(y1, y2) - 1e-8 <= py && py <= Math.max(y1, y2) + 1e-8; if (!withinXBounds || !withinYBounds) { return false; } // 计算叉积,判断点是否在直线上(考虑浮点精度) double crossProduct = (px - x1) * (y2 - y1) - (py - y1) * (x2 - x1); return Math.abs(crossProduct) < 1e-8; } }
示例使用代码
你可以这样调用工具类来测试你的五边形和目标点:
public class GeoTest { public static void main(String[] args) { // 创建你要判断的目标点 Point targetPoint = Point.fromLngLat(你的点经度, 你的点纬度); // 创建你的五边形Polygon(注意最后一个点要和第一个点重合,保证多边形闭合) List<Position> polygonVertices = List.of( Position.fromLngLat(点1经度, 点1纬度), Position.fromLngLat(点2经度, 点2纬度), Position.fromLngLat(点3经度, 点3纬度), Position.fromLngLat(点4经度, 点4纬度), Position.fromLngLat(点5经度, 点5纬度), Position.fromLngLat(点1经度, 点1纬度) // 闭合多边形 ); Polygon testPolygon = Polygon.fromLngLats(List.of(polygonVertices)); // 调用判断方法 boolean isInside = GeoUtils.isPointInPolygon(targetPoint, testPolygon); System.out.println("目标点是否在多边形内:" + isInside); } }
额外说明
- 内环处理:如果你的Polygon包含内环(比如带洞的多边形),上面的代码已经处理了这种情况——只要点在任何一个内环里,就会返回
false。 - 浮点精度:代码中用了
1e-8作为精度阈值,你可以根据业务需求调整这个值,避免因为浮点计算误差导致判断错误。 - 适用范围:这个算法适用于所有简单多边形(不自交的多边形),你的五边形只要是正常的非自交形状就完全没问题。
内容的提问来源于stack exchange,提问作者Dyst.
相关产品推荐
相关产品推荐

