前言
?
緩沖區分析是地理信息系統(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 實現空間查詢