基于 JTS 库实现地理空间缓冲区构建与点位落图分析
JTS 空间几何处理概述
Java Topology Suite(简称 JTS)是处理二维几何图形运算的核心开源库,广泛应用于 GIS 领域。它支持对点、线、面等几何对象进行创建、拓扑关系判定及复杂的空间分析。本文主要探讨如何利用 JTS 构建沿线的不规则缓冲区域,并在此基础上完成特定坐标点的归属判断及最短距离测算。
核心功能模块设计
系统流程分为四个关键步骤:首先解析经纬度序列生成线状几何体;其次根据物理半径换算为角度差以生成缓冲区多边形;接着提取多边形顶点用于前端渲染;最后遍历待检点集,验证其是否位于缓冲区内并计算至原路线的垂直距离。
一、构建线性几何对象
首先需要将输入的 JSON 格式坐标数组转换为 JTS 识别的 Geometry 对象。这里定义了坐标转换逻辑,确保高精度的数值解析。
public class SpatialGeometryService {
// 初始化几何工厂
private final GeometryFactory geoFactory = new GeometryFactory();
/**
* 解析坐标列表生成线要素
*/
public Geometry buildLinearGeometry(List<List<Double>> rawCoords) {
Coordinate[] coordArray = new Coordinate[rawCoords.size()];
int index = 0;
for (List<Double> item : rawCoords) {
coordArray[index++] = new Coordinate(item.get(0), item.get(1));
}
return geoFactory.createLineString(coordArray);
}
}
二、计算地理范围缓冲区
由于地理坐标系(如 WGS84)使用度为单位,而业务需求通常为米,需通过地球半径公式进行单位折算。本例采用赤道周长近似值进行换算,并利用 JTS 的缓冲参数定制圆角样式,使边缘更平滑。
/**
* 生成指定宽度的环绕多边形
* @param lineGeom 源线路几何体
* @param widthInMeters 缓冲宽度(单位:米)
* @return 生成的多边形对象
*/
public Geometry createBufferedZone(Geometry lineGeom, double widthInMeters) {
// 米转弧度再转度数的简化计算公式 (假设地球半径约 6371km)
double earthRadius = 6371004.0;
double degreeOffset = widthInMeters / (2 * Math.PI * earthRadius) * 360.0;
// 实例化缓冲操作器以设置高级参数
BufferOp bufferOperator = new BufferOp(lineGeom);
bufferOperator.setEndCapStyle(BufferParameters.CAP_ROUND); // 端点样式设为圆形
bufferOperator.setQuadrantSegments(8); // 增加分段数以优化圆滑度
return bufferOperator.getResultGeometry(degreeOffset);
}
}
三、点集包含性检测与距离测算
此阶段遍历目标点集合,利用空间谓词判断点是否在多边形内部。对于命中的点,进一步计算其到原始线路的最小欧氏距离,并将结果映射回业务数据中。
/**
* 批量校验点位位置状态
* @param sourceLine 原始线路对象
* @param bufferedArea 缓冲区域对象
* @param targetPoints 待检测点集合
* @return 筛选后的有效点集(含距离信息)
*/
public List<Map<String, Object>> filterPointsWithinBuffer(Geometry sourceLine,
Geometry bufferedArea,
List<Map<String, Object>> targetPoints) {
List<Map<String, Object>> validResults = new ArrayList<>();
double earthCircumference = 2 * Math.PI * 6371004.0;
for (Map<String, Object> entry : targetPoints) {
double lng = Double.parseDouble(entry.get("lng").toString());
double lat = Double.parseDouble(entry.get("lat").toString());
Point probePoint = geoFactory.createPoint(new Coordinate(lng, lat));
// 空间相交判定
if (bufferedArea.intersects(probePoint)) {
// 计算点到线的最短度数距离
double distanceDeg = sourceLine.distance(probePoint);
// 还原为米
double distanceMeters = distanceDeg * (earthCircumference / 360.0);
Map<String, Object> resultMap = new HashMap<>(entry);
resultMap.put("isInside", true);
resultMap.put("minDistance", Math.round(distanceMeters * 100.0) / 100.0);
validResults.add(resultMap);
}
}
return validResults;
}
/**
* 辅助方法:导出多边形顶点供地图绘制使用
*/
public List<Map<String, Double>> extractPolygonVertices(Geometry polygon) {
List<Map<String, Double>> vertices = new ArrayList<>();
Coordinate[] coords = polygon.getCoordinates();
for (Coordinate c : coords) {
Map<String, Double> map = new HashMap<>();
map.put("x", c.x);
map.put("y", c.y);
vertices.add(map);
}
return vertices;
}
}