作者:后端小肥肠
🍇 我写过的文章中的相关代码放到了gitee,地址:xfc-fdw-cloud: 公共解决方案
🍊 有疑问可私信或评论区联系我。
🥑 创作不易未经允许严禁转载。
本文涉及GDAL及GeoTools代码实践,基础环境搭建可查看博客:
【GIS系列】GeoTools简介及工具类分享-CSDN博客
Springboot+GDAL3.x在windows上配置开发环境_springboot集成gdal 3.0.1-CSDN博客
目录
1.前言
最近,我接了一个要求利用Java从ArcGIS的Spatial Database Engine (SDE) 数据库中读取数据进行空间叠加分析的项目需求。考虑到这个任务的复杂性,以及在网上缺乏具体的实现指导,我决定写下这篇文章,记录我在项目中的实际经验和解决方案,希望能帮助到面临类似挑战的开发者。
2. 技术路线
上述流程图可解释为以下步骤:
1. 获取SDE图层信息
第一步是连接到SDE数据库并查询可用的图层信息。这一信息是执行叠加分析的基础,需要确保连接的稳定性和数据的准确性。
2. 读取并缓存SDE中的数据集
一旦获取了必要的图层信息,下一步是从这些图层中读取数据。
3. 执行空间叠加分析
这是技术实现的核心部分。我们将缓存的SDE数据与输入的WKT数据进行叠加分析。这一步骤涉及复杂的空间算法,可能包括但不限于多边形重叠、交集和并集等操作,本文仅对相交进行实践。
4. 获取最终叠加分析结果
叠加分析完成后,我们提取分析结果。这些结果将用于报告、可视化展示或作为决策支持的数据输入。
3. sde数据准备
首先我们应该准备一些sde数据,具体步骤不演示,可查看arcgis帮助文档:教程:PostgreSQL 中地理数据库入门—帮助 | ArcGIS Desktop
数据库中查看数据,可看出空间数据以wkb形式存储:
数据拖到展示区:
本文中将以overlay3为叠加分析输入图形,以阿里节点为源图层进行叠加分析操作,我们先基于arcgis做一下叠加分析查看一下结果:
大红色部分为叠加分析(相交)结果:
4. 技术方案实现
4.1. gdal直连读取sde(失败)
GDAL是一个非常流行的地理数据处理库,支持多种地理数据格式。理论上,使用GDAL直连读取SDE数据似乎是一个有效的技术选择。我们的初衷是利用GDAL的强大功能来简化数据访问,并直接进行空间叠加分析,先通过代码获取sde中的空间要素,代码如下:
@Test
public void test3() {
// 注册所有GDAL/OGR驱动
ogr.RegisterAll();
// 定义连接字符串,确保将密码替换为实际的密码
String connection = "PG:host=127.0.0.1 port=5432 dbname='spatial_db_st' user='sde' password='admin'";
// 打开数据源
DataSource ds = ogr.Open(connection, 0);
if (ds == null) {
System.out.println("无法连接到数据库");
return;
}
System.out.println("成功连接到数据库");
System.out.println("图层列表:");
// 循环遍历所有图层并打印图层名称及其几何类型
for (int i = 0; i < ds.GetLayerCount(); i++) {
Layer layer = ds.GetLayerByIndex(i);
if (layer != null) {
String layerName = layer.GetName();
if(layerName.equals("阿里节点")||layerName.equals("规划院节点")||layerName.equals("overlay3")){
long count = layer.GetFeatureCount();
int geomType = layer.GetGeomType(); // 获取几何类型
String geomTypeName = ogr.GeometryTypeToName(geomType); // 将几何类型转换为可读名称
System.out.println((i + 1) + ": " + layerName + " 要素个数: " + count+" 几何类型:"+geomTypeName);
}
}
}
// 关闭数据源
ds.delete();
}
上述使用GDAL库的OGR组件来尝试连接到一个基于PostGIS的SDE数据库,并列出其所有图层的名称、要素个数以及几何类型。代码首先注册所有GDAL/OGR驱动,然后使用一个包含数据库连接详细信息的字符串尝试打开数据源。一旦连接成功,它遍历所有图层,并打印每个图层的名称、包含的要素数量和几何类型。最后,代码会关闭数据源以释放资源。
运行结果如下图,我们能看到,gdal打印类型为空:
为空的原因是gdal并没有提供sde相关的支持,我们运行以下命令:
ogrinfo --formats
打印的结果:
Supported Formats:
PCIDSK -raster,vector- (rw+v): PCIDSK Database File
PDS4 -raster,vector- (rw+vs): NASA Planetary Data System 4
VICAR -raster,vector- (rw+v): MIPL VICAR file
JP2OpenJPEG -raster,vector- (rwv): JPEG-2000 driver based on OpenJPEG library
PDF -raster,vector- (w+): Geospatial PDF
MBTiles -raster,vector- (rw+v): MBTiles
EEDA -vector- (ro): Earth Engine Data API
OGCAPI -raster,vector- (rov): OGCAPI
ESRI Shapefile -vector- (rw+v): ESRI Shapefile
MapInfo File -vector- (rw+v): MapInfo File
UK .NTF -vector- (rov): UK .NTF
LVBAG -vector- (rov): Kadaster LV BAG Extract 2.0
OGR_SDTS -vector- (rov): SDTS
S57 -vector- (rw+v): IHO S-57 (ENC)
DGN -vector- (rw+v): Microstation DGN
OGR_VRT -vector- (rov): VRT - Virtual Datasource
REC -vector- (ro): EPIInfo .REC
Memory -vector- (rw+): Memory
CSV -vector- (rw+v): Comma Separated Value (.csv)
GML -vector- (rw+v): Geography Markup Language (GML)
GPX -vector- (rw+v): GPX
KML -vector- (rw+v): Keyhole Markup Language (KML)
GeoJSON -vector- (rw+v): GeoJSON
GeoJSONSeq -vector- (rw+v): GeoJSON Sequence
ESRIJSON -vector- (rov): ESRIJSON
TopoJSON -vector- (rov): TopoJSON
OGR_GMT -vector- (rw+v): GMT ASCII Vectors (.gmt)
GPKG -raster,vector- (rw+vs): GeoPackage
SQLite -vector- (rw+v): SQLite / Spatialite
ODBC -vector- (ro):
WAsP -vector- (rw+v): WAsP .map format
PGeo -vector- (ro): ESRI Personal GeoDatabase
MSSQLSpatial -vector- (rw+): Microsoft SQL Server Spatial Database
OpenFileGDB -vector- (rov): ESRI FileGDB
DXF -vector- (rw+v): AutoCAD DXF
CAD -raster,vector- (rovs): AutoCAD Driver
FlatGeobuf -vector- (rw+v): FlatGeobuf
Geoconcept -vector- (rw+v): Geoconcept
GeoRSS -vector- (rw+v): GeoRSS
GPSTrackMaker -vector- (rw+v): GPSTrackMaker
VFK -vector- (ro): Czech Cadastral Exchange Data Format
PGDUMP -vector- (w+v): PostgreSQL SQL dump
OSM -vector- (rov): OpenStreetMap XML and PBF
GPSBabel -vector- (rw+): GPSBabel
OGR_PDS -vector- (rov): Planetary Data Systems TABLE
WFS -vector- (rov): OGC WFS (Web Feature Service)
OAPIF -vector- (ro): OGC API - Features
Geomedia -vector- (ro): Geomedia .mdb
EDIGEO -vector- (rov): French EDIGEO exchange format
SVG -vector- (rov): Scalable Vector Graphics
CouchDB -vector- (rw+): CouchDB / GeoCouch
Cloudant -vector- (rw+): Cloudant / CouchDB
Idrisi -vector- (rov): Idrisi Vector (.vct)
ARCGEN -vector- (rov): Arc/Info Generate
XLS -vector- (ro): MS Excel format
ODS -vector- (rw+v): Open Document/ LibreOffice / OpenOffice Spreadsheet
XLSX -vector- (rw+v): MS Office Open XML spreadsheet
Elasticsearch -vector- (rw+): Elastic Search
Walk -vector- (ro):
Carto -vector- (rw+): Carto
AmigoCloud -vector- (rw+): AmigoCloud
SXF -vector- (rov): Storage and eXchange Format
Selafin -vector- (rw+v): Selafin
JML -vector- (rw+v): OpenJUMP JML
PLSCENES -raster,vector- (ro): Planet Labs Scenes API
CSW -vector- (ro): OGC CSW (Catalog Service for the Web)
VDV -vector- (rw+v): VDV-451/VDV-452/INTREST Data Format
MVT -vector- (rov): Mapbox Vector Tiles
NGW -raster,vector- (rw+s): NextGIS Web
MapML -vector- (rw+v): MapML
TIGER -vector- (rw+v): U.S. Census TIGER/Line
AVCBin -vector- (rov): Arc/Info Binary Coverage
AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage
HTTP -raster,vector- (ro): HTTP Fetching Wrapper
从打印的结果来看,gdal不提供sde相关技术支持,这个方案宣布作废╮(╯▽╰)╭。
4.2 postgis读取sde数据做空间分析叠加(失败)
在第3章中我们可以看出sde中空间数据是以wkb的方式存储,那么能不能借助postgis的方式实现呢?二话不说先写一个sql来运行看看:
SELECT
"objectid",
ST_AsText(ST_Intersection(shape, ST_GeomFromText('POLYGON ((...))'))) AS intersection_geometry
FROM
"sde"."阿里节点"
WHERE
ST_Intersects(shape, ST_GeomFromText('POLYGON ((...))'));
这段SQL查询旨在从名为“阿里节点”的表中检索与指定多边形相交的几何要素对象。首先使用ST_GeomFromText
函数将WKT字符串转换为几何对象,然后通过ST_Intersects
函数筛选出表中与该多边形空间相交的记录。对于每个找到的相交记录,使用ST_Intersection
函数计算实际的交集区域,并将结果几何形状转换为文本格式输出。
运行结果如下:
报错没有ST_GeomFromText这个函数,postgis读取sde数据做空间分析叠加这个方案再次宣告失败。
4.3. 基于geotools进行叠加分析
引入maven依赖:
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>28.3</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>28.3</version>
</dependency>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.18.1</version> <!-- 最新的 JTS 版本 -->
</dependency>
基于geotools进行叠加分析代码如下:
@Test
public void test1() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 1. 连接到数据库
conn = DriverManager.getConnection(DB_URL, USER, PASS);
System.out.println("成功连接到数据库");
// 2. 查询 "阿里节点" 表的几何字段 shape(以 WKT 格式输出)
String sql = "SELECT objectid, ST_AsText(shape) AS wkt_shape FROM sde.\"阿里节点\" WHERE objectid = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 2); // 查询 objectid 为 1 的记录,您可以根据需要更改
rs = pstmt.executeQuery();
// 3. 获取查询结果
if (rs.next()) {
String wktFromDatabase = rs.getString("wkt_shape");
// System.out.println("从数据库中获取的 WKT: " + wktFromDatabase);
// 4. 将数据库中的 WKT 与另一个输入的 WKT 进行叠加分析
String externalWkt = "POLYGON(( 85.71074699 34.77325272 0.00000000, 84.53150517 32.55857906 0.00000000, 88.93209050 31.20676526 0.00000000, 89.70866438 33.73782088 0.00000000, 85.71074699 34.77325272 0.00000000))";
WKTReader reader = new WKTReader();
// 解析数据库中查询到的 WKT 和外部提供的 WKT
Geometry geomFromDb = reader.read(wktFromDatabase);
Geometry externalGeom = reader.read(externalWkt);
// 检查是否相交
if (geomFromDb.intersects(externalGeom)) {
System.out.println("几何体相交!");
Geometry intersection = geomFromDb.intersection(externalGeom);
System.out.println("相交区域的 WKT 表示: " + intersection.toText());
} else {
System.out.println("几何体不相交。");
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} finally {
// 5. 关闭资源
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上述代码从数据库中读取特定记录的地理空间数据,并与外部提供的WKT(Well-Known Text)格式的多边形进行空间叠加分析。首先,代码通过JDBC连接到数据库,并使用PreparedStatement
执行SQL查询,以获取objectid
为2的记录的shape
字段。接着,使用JTS(Java Topology Suite)库的WKTReader
来解析从数据库中得到的WKT以及外部定义的WKT,然后检查这两个几何体是否相交。如果它们相交,将计算并输出它们的交集区域。
结果打印:
在可视化的工具中验证一下wkt:
从上图可看出代码运行的结果与我们在arcgis中进行叠加分析的结果是一致的。
5. 结语
在本文中,我们探讨了如何使用Java从ArcGIS的SDE数据库读取数据并进行空间叠加分析。虽然在尝试中遇到了一些挑战,但通过应用GeoTools框架,我们最终成功实现了所需功能。这次经验强调了在GIS开发中灵活选择和应用技术的重要性。
感谢大家的阅读,希望这篇文章能为相关开发者提供帮助。如有疑问或进一步讨论的需求,欢迎留言或私信联系我。让我们继续探索GIS的世界,共同推动技术发展。