提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
gis通过GeometryFactory 进行绘制缓冲区,并校验坐标点是否在缓冲区内
通过java来实现缓冲区绘制及点校验
一、缓冲区是什么?
GIS缓冲区是地理信息系统(GIS)中的一种空间分析功能,它指的是围绕地理对象(如点、线、多边形实体)一定宽度的区域,用于分析地理对象的影响范围或服务范围。
缓冲区分析在GIS中扮演着重要的角色,它不仅可以用来分析地理对象的影响范围,如化工厂排放废气的污染范围或服务范围,洪涝灾害的淹没区,还可以用来表示地理现象的服务范围,如河流的灌溉范围、电力线路的供电范围、超市、医院的服务范围等。缓冲区分析通过计算在点、线、多边形实体周围自动形成满足一定距离要求的区域,这些区域通常用于确定影响范围,是气候评价应用比较多的另一个空间分析功能。
缓冲区的建立有三种基本情况:一是基于点要素的缓冲区,通常以点为圆心、以一定距离为半径的圆;二是基于线要素的缓冲区,通常是以线为中心轴线,距中心轴线一定距离的平行条带多边形;三是基于面要素多边形边界的缓冲区,向外或向内扩展一定距离以生成新的多边形。这种分析方法在农业、城市规划、生态保护等诸多领域都有广泛的应用,是实现数据在二维空间扩展的信息分析方法之一
二、使用步骤
Maven 依赖
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.19.0</version>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
代码
缓冲区生成
/**
* 线缓冲区生成
* @param distance 距离(米)
* @param lineStr 线列表 116.403322,39.920255;116.392651,39.914283;116.405433,39.910075
* @return 缓冲区坐标
*/
public static String getGeometry(double distance,String lineStr) {
GeometryFactory geometryFactory = new GeometryFactory();
//没有线坐标或者没有距离时直接返回
if(StrUtil.isBlank(lineStr) || distance<1){
return lineStr;
}
String[] lines = lineStr.split(";");
Coordinate[] coordinates = new Coordinate[lines.length];
for (int i = 0; i < lines.length; i++) {
String[] lngLat = lines[i].split(",");
Coordinate coordinate = new Coordinate(Double.parseDouble(lngLat[0]),Double.parseDouble(lngLat[1]));
coordinates[i] = coordinate;
}
// 创建一条线
LineString line = geometryFactory.createLineString(coordinates);
// 缓冲区半径
double bufferDistance = metersToDegrees(distance);
// System.out.println(bufferDistance);
//米 = 缓冲区距离(度) * 111,000 * cos(纬度 * π / 180)
// System.out.println(bufferDistance);
// 缓冲区参数
BufferParameters bufferParameters = new BufferParameters();
bufferParameters.setEndCapStyle(BufferParameters.CAP_SQUARE);
bufferParameters.setJoinStyle(BufferParameters.JOIN_ROUND);
// 设置四分之一段数,控制圆角的平滑程度
bufferParameters.setQuadrantSegments(8);
// 缓冲区操作
BufferOp bufferOp = new BufferOp(line, bufferParameters);
// 计算缓冲区
Geometry bufferGeometry = bufferOp.getResultGeometry(bufferDistance);
// 输出缓冲区的WKT表示
// System.out.println(bufferGeometry.toText());
return Arrays.stream(bufferGeometry.getCoordinates()).map(point->point.x+","+ point.y).collect(Collectors.joining(";"));
}
将米转换为度
// 地球在赤道的平均半径,单位:米
private static final double EARTH_RADIUS = 6371000;
/**
* 将米转换为经纬度上的角度变化(以度为单位)。
* 这是一个简化的计算,没有考虑地球的椭球形状和具体的地理位置。
*
* @param meters 距离,单位:米
* @return 角度变化,单位:度
*/
public static double metersToDegrees(double meters) {
// 将米转换为弧度
double radians = meters / EARTH_RADIUS;
// 将弧度转换为度
return Math.toDegrees(radians);
}
校验是否在缓冲区内
代码如下:
/**
* 判断是否在多边形区域内
*
* @param pointStr 要判断的点坐标
* @param pointsStr 边界点列表,多个坐标分号分隔,经纬度逗号分隔
* @return boolean
*/
public static boolean isInPolygon(String pointStr, String pointsStr) {
if (StrUtil.isBlank(pointStr) || StrUtil.isBlank(pointsStr) || !pointsStr.contains(",") || pointStr.contains("null") || pointsStr.contains("null")) {
return false;
}
String[] p = pointStr.split(",");
// 将要判断的横纵坐标组成一个点
Point2D.Double point = new Point.Double(Double.parseDouble(p[0]), Double.parseDouble(p[1]));
// 将区域各顶点的横纵坐标放到一个点集合里面
List<Point2D.Double> polygon = Arrays.stream(pointsStr.split(";")).map(e -> {
String[] poPoint = e.split(",");
return new Point2D.Double(Double.parseDouble(poPoint[0]), Double.parseDouble(poPoint[1]));
}).collect(Collectors.toList());
return check(point, polygon);
}
/**
* 一个点是否在多边形内
*
* @param point 要判断的点的横纵坐标
* @param polygon 组成的顶点坐标集合
* @return boolean
*/
private static boolean check(Point2D.Double point, List<Point2D.Double> polygon) {
java.awt.geom.GeneralPath peneralPath = new java.awt.geom.GeneralPath();
Point2D.Double first = polygon.get(0);
// 通过移动到指定坐标(以双精度指定),将一个点添加到路径中
peneralPath.moveTo(first.x, first.y);
polygon.remove(0);
for (Point2D.Double d : polygon) {
// 通过绘制一条从当前坐标到新指定坐标(以双精度指定)的直线,将一个点添加到路径中。
peneralPath.lineTo(d.x, d.y);
}
// 将几何多边形封闭
peneralPath.lineTo(first.x, first.y);
peneralPath.closePath();
// 测试指定的 Point2D 是否在 Shape 的边界内。
return peneralPath.contains(point);
}
样例
public static void main(String[] args) {
String geometry = getGeometry(50,"118.046541,36.869478;118.045225,36.868597;118.045217,36.868739");
System.out.println("缓冲区:"+geometry);
System.out.println("是否在缓冲区内:"+isInPolygon(geometry,"116.555,38.555"));
}