目录
前言
在当今数字化时代,地理空间数据的应用愈发广泛,而海图作为重要的地理信息资源,在航海、海洋研究等领域扮演着关键角色。S57 海图文件作为一种标准化的海图数据格式,承载着丰富的海洋地理信息,如何高效、准确地读取和解析这些数据,成为了众多开发者和研究人员关注的焦点。近期有朋友与我交流,想了解S57海图文件的读取与发布。海图文件我其实没有接触过,所以对其也是一无所知。因此今天,就让我们一同走进这场基于 JAVA 和 GDAL 的 S57 海图文件解析实战之旅,探索其中的技术奥秘与实践要点。
在开始实战之前,我们需要对相关技术背景有所了解。JAVA 作为一种成熟且广泛应用的编程语言,以其强大的跨平台特性、丰富的类库和良好的性能,为处理各种复杂任务提供了坚实基础。而 GDAL(Geospatial Data Abstraction Library)则是一个开源的地理空间数据抽象库,它支持多种地理空间数据格式的读写操作,包括 S57 海图文件。将 JAVA 与 GDAL 结合,能够充分发挥两者的优势,实现对 S57 海图文件的高效解析。通过本次实战,我们将逐步深入,从搭建开发环境、配置相关依赖,到编写代码实现对 S57 海图文件的读取、解析以及数据提取等操作,全方位展示整个过程,让读者能够清晰地掌握每个环节的关键点。
这场实战不仅仅是对技术的实践应用,更是一次对地理空间数据处理领域的深入探索。在解析 S57 海图文件的过程中,我们会遇到各种数据结构、编码方式以及地理空间概念等问题,通过解决这些问题,我们能够更好地理解地理空间数据的内在逻辑和处理方法。此外,本次实战也将分享一些常见问题的解决方案和优化技巧,帮助读者在实际开发中避免遇到类似的困境。无论你是地理信息系统领域的开发者,还是对地理空间数据处理感兴趣的程序员,相信通过本文的介绍,你都将收获满满,为今后在相关领域的项目开发和个人学习奠定坚实的基础。
一、海图文件简介
为了让大家对海图文件有一个简单的了解,本节将对海图文件进行一个简单的介绍。由于之前也没有接触过海图文件,因此也是自己的学习过程。信息记录比较简单,在以后的学习中不断补充完善。首先给大家介绍依稀海图文件是什么?然后以S57为例具体介绍海图文件的文件类型。
1、什么是海图文件
海图文件是一种用于表示海洋地理信息的数字文件格式,它包含了海洋地形、水深、航行障碍物、海岸线、航标等重要地理信息。这些信息对于航海安全、海洋资源开发、海洋科学研究以及军事应用等领域至关重要。海图文件通常以矢量或栅格数据的形式存储,能够为船舶导航系统、地理信息系统(GIS)以及相关海洋应用提供基础数据支持。
2、S57海图文件
S57 海图文件是一种国际标准化的矢量海图数据格式,由国际水道测量组织(IHO)制定并广泛应用于全球海洋领域。S57 文件格式具有以下特点:
-
标准化:S57 格式遵循 IHO 的 S-57 标准,确保了不同国家和地区之间的海图数据可以无缝交换和互操作。
-
矢量数据:S57 文件以矢量形式存储地理信息,包括点、线、面等几何对象,能够提供高精度的地理数据表示。
-
丰富的属性信息:除了几何数据外,S57 文件还包含了大量的属性信息,如水深、地形类型、航行警告等,这些属性信息为用户提供了更全面的海洋地理信息。
-
分层存储:S57 文件支持分层存储,用户可以根据需要选择显示或处理特定的图层,提高了数据处理的灵活性和效率。
-
兼容性:S57 文件格式被广泛应用于各种航海设备和地理信息系统软件中,具有良好的兼容性。
S57 海图文件的这些特点使其成为海洋地理信息领域的重要数据格式之一。通过解析 S57 文件,开发者可以提取出丰富的地理信息,用于开发各种海洋应用,如船舶导航系统、海洋环境监测、海洋资源管理等。
二、QGIS读取S57实现
在了解了S57海图文件后,接下来以QGIS为例,来看看海图文件展示出来是什么样子。从图层信息和属性信息查看两个方面进行介绍。
1、图层展示
为演示海图文件的加载,从C站获取网友提供的海图文件。下载后得到的S57海图信息如下:

然后在QGIS中打开这些文件,与shp文件不一样。海图文件通常包含51个图层,以C1313100.000这个文件为例。使用QGIS打开后可以看到有以下提示:

点击"OK"按钮将图层添加到图层组中,如下图所示:

在Qgis的左边可以看到所有的图层信息,我们可以打开任意的一个图层文件查看文件信息。如下图所示:

2、属性查看
图层信息比较多,这里我们不一一的对其进行查看。跟shp文件一样,我们来看看其属性信息都包含哪些呢?在Qgis中我们先来看看图层有哪些属性。在信息中可以看到以下信息:

可以看到这个图层大约有30个字段。再来看看属性表中这些信息度包含哪些内容。

这些数据跟我们常用的数据库类似,都是一条一条的记录。
三、GDAL读取S57实现
除了可以使用Qgis来打开读取S57文件,我们还可以使用GDAL来进行海图文件的读取。目前很多对海图文件的读取都是C或者C++为主,还有Python的。但是介绍Java的读取的不多,因此本文也算是一个简单的补充。对广大的Java GIS 开发这有一个参考。
1、Maven引用
这里使用一种比较简单的方式引入GDAL的jar,需要注意的是,在Java中要提前配置好GDAL的环境才可以,关于GDAL的java环境配置,可以翻阅之前的博客,有详细的介绍。这里贴出jar引用代码:
XML
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yelang</groupId>
<artifactId>gdal_demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gdal_demo1</name>
<description>gdal的第一次试验</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.gdal</groupId>
<artifactId>gdal</artifactId>
<version>3.4.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/gdal.jar</systemPath>
</dependency>
<dependency>
<groupId>net.sf.ucanaccess</groupId>
<artifactId>ucanaccess</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/de.micromata.jak/JavaAPIforKml -->
<dependency>
<groupId>de.micromata.jak</groupId>
<artifactId>JavaAPIforKml</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
</project>
2、Java读取
为了实现Java调用GDAL实现S57文件的读取,我们首先来看看应该调用什么驱动来进行读取。首先看看GDAL官网有没有提供相关说明:

在官网上可以看到有对应的驱动,点开S57后,可以看到以下的描述:

在GDAL中要实现S57文件的读取的驱动使用"S57"即可。下面给出具体的Java读取代码:
java
package com.yelang.s57;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gdal.gdal.gdal;
import org.gdal.ogr.DataSource;
import org.gdal.ogr.Feature;
import org.gdal.ogr.FeatureDefn;
import org.gdal.ogr.FieldDefn;
import org.gdal.ogr.Geometry;
import org.gdal.ogr.Layer;
import org.gdal.ogr.ogr;
import org.gdal.osr.SpatialReference;
import org.junit.Test;
public class GdalS57Case {
@Test
public void readS572() {
// 指定文件的名字和路径
String strVectorFile = "path/海图文件/TestChart/TestChart/C1313100.000";
// 注册所有的驱动
ogr.RegisterAll();
// 为了支持中文路径,请添加下面这句代码
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
// 为了使属性表字段支持中文,请添加下面这句
gdal.SetConfigOption("SHAPE_ENCODING", "CP936");
// 读取数据,这里以ESRI的shp文件为例
String strDriverName = "S57";
// 创建一个文件,根据strDriverName扩展名自动判断驱动类型
org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
if (oDriver == null) {
System.out.println(strDriverName + " 驱动不可用!\n");
return;
}
DataSource dataSource = oDriver.Open(strVectorFile);
int totalCount = dataSource.GetLayerCount();
for (int i = 0; i < dataSource.GetLayerCount(); i++) {
Layer layer = dataSource.GetLayer(i);
SpatialReference srf = layer.GetSpatialRef();
String srfStr = null == srf ? "空" : "空间参考坐标系:" + srf.GetAttrValue("AUTHORITY", 0)+ srf.GetAttrValue("AUTHORITY", 1);
String srid = null == srf ? "-" : srf.GetAttrValue("AUTHORITY", 1);
System.out.println("图层名称:<==>" + layer.GetName() + "\t" + srfStr + "\t" + srid);
long featureCount = layer.GetFeatureCount();
System.out.println("数据量大小==>" + featureCount);
// 获取所有的字段名
List<String> fieldNames = new ArrayList<String>();
FeatureDefn featureDefn = layer.GetLayerDefn();
for (int j = 0; j < featureDefn.GetFieldCount(); j++) {
FieldDefn fieldDefn = featureDefn.GetFieldDefn(j);
String fields = fieldDefn.GetName();
fieldNames.add(fields);
}
//System.out.println("所有字段名:" + fieldNames);
// 遍历读取属性
Feature feature = null;
while ((feature = layer.GetNextFeature()) != null) {
List<String> fieldValue = new ArrayList<String>();
Geometry geometry = feature.GetGeometryRef();
if(null != geometry) {
String geojson = feature.GetGeometryRef().ExportToJson();
System.out.println("geojson :" + geojson);
}
StringBuffer sbf = new StringBuffer(1024);
// 遍历字段名读取所有属性
for (String fieldName : fieldNames) {
String field = feature.GetFieldAsString(fieldName);
fieldValue.add(field);
//System.out.println(fieldName +"===>"+field);
sbf.append(fieldName + "=" + field + ";");
}
System.out.println(sbf.toString());
}
System.out.println("---------------------------------------------------");
}
System.out.println("总图层数:" + totalCount);
dataSource.delete();
gdal.GDALDestroyDriverManager();
}
}
可以看到,对S57海图文件的解析与shp文件的解析基本一致。读取layer,然后就获取feature,获取属性解析输出即可。
3、读取成果输出
最后来看看使用Java调用GDAL对S57文件进行解析后的属性和空间信息,在控制台输出如下:

bash
图层名称:<==>C_AGGR 空 -
数据量大小==>2
RCID=2544;PRIM=255;GRUP=2;OBJL=400;RVER=1;AGEN=71;FIDN=-1375794613;FIDS=73;LNAM=0047ADFF0A4B0049;LNAM_REFS=(34:0047583709140094,00470394B3E5002A,0047583709150094,004719A4545F0028,0047B20623220027,00475837090E0094,0047639BC6210029,00475837090F0094,0047B696F02A001D,0047583709170094,0047FD1733EF001A,0047583709160094,00477604421B001B,0047460172EB001F,0047F83ED80B0003,004700757E65004D,0047583709180094,0047CFEA4BE70020,0047583709190094,004792801E360025,00475837091B0094,0047722AB7040021,00475837091A0094,00471AF81A8F0024,0047D5A9B55C001C,0047C35F10640048,0047566D45AA0091,0047EBD02F660047,0047BEFD2A3A0022,00475705DC260092,004700757E78004D,00470112A9790012,0047599563800001,00474BDBE3B40002);FFPT_RIND=(34:3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3);NOBJNM=;OBJNAM=;INFORM=;NINFOM=;NTXTDS=;PICREP=;SCAMAX=;SCAMIN=;TXTDSC=;RECDAT=;RECIND=;SORDAT=;SORIND=;
RCID=2815;PRIM=255;GRUP=2;OBJL=400;RVER=1;AGEN=71;FIDN=950957764;FIDS=1;LNAM=004738AE76C40001;LNAM_REFS=(7:00470DDA54C0005A,0047C7096211005B,0047010366DD0011,00471E6602920033,00471E6602930033,00470112A8FE0012,00470112A90D0012);FFPT_RIND=(7:3,3,3,3,3,3,3);NOBJNM=;OBJNAM=;INFORM=;NINFOM=;NTXTDS=;PICREP=;SCAMAX=;SCAMIN=;TXTDSC=;RECDAT=;RECIND=;SORDAT=;SORIND=;
---------------------------------------------------
四、总结
以上就是本文的主要内容,本次实战,我们将逐步深入,从搭建开发环境、配置相关依赖,到编写代码实现对 S57 海图文件的读取、解析以及数据提取等操作,全方位展示整个过程,让读者能够清晰地掌握每个环节的关键点。这场实战不仅仅是对技术的实践应用,更是一次对地理空间数据处理领域的深入探索。海图文件繁多,可以做很多深入的研究,受限文章篇幅,这里不进行赘述。抛砖引玉,大家可以对功能进行扩展。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。