前言
❝
缓冲区分析是地理信息系统(GIS)空间分析的核心功能之一。它通过围绕点、线或面等地理实体,自动生成指定距离(或宽度)的等距区域(缓冲区)。该功能为量化空间邻近度、评估影响范围、识别潜在冲突或关联区域提供了基础而强大的工具,是理解空间关系、支持空间决策不可或缺的重要手段。
本篇教程在之前一系列文章的基础上讲解如何将使用GeoTools
工具结合OpenLayers
实现空间数据的空间缓冲区分析功能。
- GeoTools 开发环境搭建[1]
- 将 Shp 导入 PostGIS 空间数据的五种方式(全)[2]
- GeoTools 结合 OpenLayers 实现空间查询[3]
如果你还没有看过,建议从那里开始。
1. 开发环境
本文使用如下开发环境,以供参考。
时间:2025年
GeoTools:v34-SNAPSHOT
IDE:IDEA2025.1.2
JDK:v17
OpenLayers:v9.2.4
Layui:v2.9.14
2. 搭建后端服务
在项目接口层创建SpatialAnalyseController
空间分析控制器。声明缓冲区分析需要的参数一个Geometry类型的GeoJSON标准对象和一个缓冲距离对象。
package com.example.geotoolsboot.controller;import com.example.geotoolsboot.service.ISpatialAnalyseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;/*** @name: SpatialAnalyseController* @description: 空间分析控制器* @author: gis_road* @date: 2025-08-05*/
@CrossOrigin(origins = "*") // 允许跨域
@RestController
public class SpatialAnalyseController {@Autowiredprivate ISpatialAnalyseService spatialAnalyseService;@GetMapping("/bufferAnalyse")public Map<String,Object> bufferAnalyse(@RequestParam() String geoJSON, Float bufferDistance){return spatialAnalyseService.bufferAnalyse(geoJSON,bufferDistance);}
}
在服务层创建ISpatialAnalyseService
接口并定义缓冲分析方法。
package com.example.geotoolsboot.service;import java.util.Map;/*** @name: ISpatialAnalyseService* @description: 空间分析服务层* @author: gis_road* @date: 2025-08-05*/
public interface ISpatialAnalyseService {Map<String,Object> bufferAnalyse(String geoJSON,Float bufferDistance);
}
在服务层中实现ISpatialAnalyseService
接口。首先将前端传递过来的Geomery GeoJSON字符串对象转换为GeoTools中的Geometry对象,之后便可以调用buffer
方法创建缓冲区对象,最后将缓冲分析结果再转换为GeoJSON对象并返回给前端。
package com.example.geotoolsboot.service.impl;import com.example.geotoolsboot.service.ISpatialAnalyseService;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.Geometry;
import org.springframework.stereotype.Service;import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;/*** @name: SpatialAnalyseServiceImpl* @description: 空间分析实现层* @author: gis_road* @date: 2025-08-05*/@Service
public class SpatialAnalyseServiceImpl implements ISpatialAnalyseService {@Overridepublic Map<String,Object> bufferAnalyse(String geoJSON,Float bufferDistance) {Map<String,Object> resultMap = new HashMap<>();// 读取GeoJSON几何对象GeometryJSON geometryJSON = new GeometryJSON(15);StringReader reader = new StringReader(geoJSON);try{Geometry geometry = geometryJSON.read(reader);// 根据距离创建缓冲对象Geometry geoBuffer = geometry.buffer(bufferDistance);// 将缓冲结果转换为Geometry GeoJSON对象StringWriter writer = new StringWriter();geometryJSON.write(geoBuffer,writer);String geoBufferJSON = writer.toString();resultMap.put("data",geoBufferJSON);}catch (Exception e){e.printStackTrace();}return resultMap;}
}
3. OpenLayers 加载缓冲对象
本文前端使用OpenLayers
结合Layui
框架实现。为了方便控制缓冲区生成距离,本文使用坐标系为投影坐标系,具体EPSG为4522。
缓冲区分析面板CSS结构。
.query-wrap {position: absolute;padding: 10px;top: 80px;left: 90px;background: #ffffff;width: 250px;border-radius: 2.5px;
}
HTML结构。
<div class="query-wrap"><form class="layui-form layui-form-pane" action=""><div class="layui-form-item"><label class="layui-form-label">绘制对象</label><div class="layui-input-block"><select name="condition" lay-filter="draw-select-filter"><option value="None">请选择绘制类型</option><option value="Point">点</option><option value="LineString">线</option><option value="Polygon">面</option></select></div></div><div class="layui-form-item"><label class="layui-form-label">缓冲距离</label><div class="layui-input-block"><input type="text" name="bufferDistance" lay-verify="required" placeholder="缓冲距离(m)"autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><button lay-submit lay-filter="clearAll" class="layui-btn layui-btn-primary">清除</button><button class="layui-btn" lay-submit lay-filter="spatialAnalyse">确认</button></div></form>
</div>
前端实现代码如下,逻辑也很简单。
let drawInteraction = null // 绘制控件
let geoJSON = null // 绘制的Geometry GeoJSON对象
let bufferDistance = 0 // 缓冲距离layui.use(['form'], function () {const form = layui.form;const layer = layui.layer;// 绘制事件form.on('select(draw-select-filter)', function (data) {removeInteraction()const value = data.value; // 获得被选中的值drawShape(value)});// 清除事件form.on("submit(clearAll)", function (data) {// 清除绘制事件removeInteraction()// 清除图形removeAllLayer(map)return false; // 阻止默认 form 跳转})// 提交事件form.on('submit(spatialAnalyse)', function (data) {if (!geoJSON) {layer.msg("请绘制缓冲区域")return false}const bufferDistance = +data.field.bufferDistanceif (!bufferDistance) {layer.msg("请输入缓冲距离")return false}const queryParam = encodeURIComponent(geoJSON)// 后端服务地址const JSON_URL = `http://127.0.0.1:8080/bufferAnalyse?geoJSON=${queryParam}&bufferDistance=${bufferDistance}`fetch(JSON_URL).then(response => response.json().then(result => {removeLayerByName("bufferLayer", map)const bufferJSON = JSON.parse(result.data)const feature = new ol.Feature({type: "Feature",geometry: new ol.format.GeoJSON().readGeometry(bufferJSON)})const vectorSource = new ol.source.Vector({features: [feature],format: new ol.format.GeoJSON()})// 缓冲区图层const bufferLayer = new ol.layer.Vector({source: vectorSource,style: new ol.style.Style({fill: new ol.style.Fill({color: "#e77b7e8f"}),stroke: new ol.style.Stroke({color: "#da4736c2",width: 2.5,}),})})bufferLayer.set("layerName", "bufferLayer")map.addLayer(bufferLayer)map.getView().fit(feature.getGeometry().getExtent())}))return false; // 阻止默认 form 跳转});
});
创建drawShape
函数,用于绘制点、线和面等几何类型,removeInteraction
方法用于移除绘制控件。需要监听绘制完成事件,当绘制结束后,读取绘制要素并获取Geometry
对象。
/*** 根据几何类型绘制几何对象*/
function drawShape(type) {const drawSource = new ol.source.Vector({ wrapX: false })const drawLayer = new ol.layer.Vector({source: drawSource,style})drawLayer.setZIndex(999)map.addLayer(drawLayer)geoJSON = nullif (type === "None") {removeInteraction()// 清除图形drawSource.clear()return}let geometryFunction = nulldrawInteraction = new ol.interaction.Draw({source: drawSource,type,geometryFunction,style,// freehand: true // 是否开启自由绘制模式})map.addInteraction(drawInteraction)drawInteraction.on('drawend', evt => {const feature = evt.featureconst featObj = new ol.format.GeoJSON().writeFeature(feature)const geomtObj = new ol.format.GeoJSON().writeGeometry(feature.getGeometry())// 存储绘制对象geoJSON = geomtObj})}// 移除绘制控件
function removeInteraction() {if (drawInteraction) {map.removeInteraction(drawInteraction)}
}
参考资料
[1]GeoTools 开发环境搭建
[2]将 Shp 导入 PostGIS 空间数据的五种方式(全)
[3]GeoTools 结合 OpenLayers 实现空间查询