如何使用Java GeoTools库实现多边形范围的点位查询
Java GeoTools实现多边形范围点位查询方案
前置依赖
首先确保项目中引入GeoTools核心模块,需要用到gt-main(包含JTS几何工具核心能力)、gt-referencing(涉及坐标系转换时需要用到)。
实现步骤
1. 构造查询多边形
首先将地图上绘制的多边形边界坐标,按顺序组装为GeoTools(底层依赖JTS)识别的Polygon对象,注意多边形坐标必须首尾闭合,且和存储的点位使用完全一致的空间坐标系。
示例代码:
import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Polygon; // 初始化几何构造工厂,SRID要和点位数据保持一致,WGS84经纬度一般填4326 GeometryFactory geoFactory = new GeometryFactory(); // 按绘制顺序填入多边形边界点,最后一个点坐标和第一个点完全相同,实现多边形闭合 Coordinate[] polygonCoordinates = new Coordinate[]{ new Coordinate(-124.71, 49.38), new Coordinate(-66.95, 49.38), new Coordinate(-66.95, 24.52), new Coordinate(-124.71, 24.52), new Coordinate(-124.71, 49.38) }; Polygon queryArea = geoFactory.createPolygon(polygonCoordinates); // 校验多边形是否合法,避免自交、不闭合等问题导致判断错误 if (!queryArea.isValid()) { throw new IllegalArgumentException("输入的多边形几何不合法"); }
2. 点位范围判断
如果你的List<Point>里存储的是JTS的Point类型,直接调用JTS内置的空间关系方法即可判断点位是否落在多边形内:
- 用
point.within(queryArea):判断点严格在多边形内部,不包含落在多边形边界上的点 - 用
point.coveredBy(queryArea):判断点在多边形内部或边界上,大部分业务场景用这个更符合预期
基础遍历实现代码:
import org.locationtech.jts.geom.Point; import java.util.ArrayList; import java.util.List; public List<Point> filterPointsInArea(List<Point> allPoints, Polygon queryArea) { List<Point> matchPoints = new ArrayList<>(); for (Point point : allPoints) { if (point.coveredBy(queryArea)) { matchPoints.add(point); } } return matchPoints; }
如果你存储的Point是自定义的经纬度实体类,先把经纬度值取出转成JTS Point对象再判断即可:
// 假设自定义点位类是MyPoint,有getLng()、getLat()方法获取经纬度 Point jtsPoint = geoFactory.createPoint(new Coordinate(myPoint.getLng(), myPoint.getLat()));
3. 大数据量性能优化
如果点位量级在十万级以上,直接全量遍历性能较差,可以用JTS自带的STRtree空间索引做预过滤,查询效率可以提升1~2个数量级:
import org.locationtech.jts.index.strtree.STRtree; import java.util.List; // 索引只需要在程序初始化/点位数据加载完成后构建一次,不需要每次查询重建 STRtree pointSpatialIndex = new STRtree(); for (Point point : points) { pointSpatialIndex.insert(point.getEnvelopeInternal(), point); } pointSpatialIndex.build(); // 查询时先通过索引快速拿到外接矩形和多边形重叠的候选点位,再做精确判断 List<Point> candidatePoints = pointSpatialIndex.query(queryArea.getEnvelopeInternal()); List<Point> finalResult = new ArrayList<>(); for (Point candidate : candidatePoints) { if (candidate.coveredBy(queryArea)) { finalResult.add(candidate); } }
效果参考
注意事项
- 多边形和点位的空间参考(SRID)必须完全一致,比如不能一个用WGS84经纬度、一个用Web墨卡托投影坐标,否则判断结果完全错误,涉及坐标系不一致时要先做坐标转换
- 构造多边形时不要出现坐标顺序混乱、自交、不闭合的问题,一定要调用
isValid()方法校验合法性 - 不要用
contains方法做判断,该方法在点恰好落在多边形边界时会返回false,边界场景容易出问题
内容的提问来源于stack exchange,提问作者杨振宁
相关产品推荐
相关产品推荐

