JAVA使用GDAL解析S57海圖文件全面詳解
前言
在當(dāng)今數(shù)字化時代,地理空間數(shù)據(jù)的應(yīng)用愈發(fā)廣泛,而海圖作為重要的地理信息資源,在航海、海洋研究等領(lǐng)域扮演著關(guān)鍵角色。S57 海圖文件作為一種標(biāo)準(zhǔn)化的海圖數(shù)據(jù)格式,承載著豐富的海洋地理信息,如何高效、準(zhǔn)確地讀取和解析這些數(shù)據(jù),成為了眾多開發(fā)者和研究人員關(guān)注的焦點(diǎn)。近期有朋友與我交流,想了解S57海圖文件的讀取與發(fā)布。海圖文件我其實(shí)沒有接觸過,所以對其也是一無所知。因此今天,就讓我們一同走進(jìn)這場基于 JAVA 和 GDAL 的 S57 海圖文件解析實(shí)戰(zhàn)之旅,探索其中的技術(shù)奧秘與實(shí)踐要點(diǎn)。
在開始實(shí)戰(zhàn)之前,我們需要對相關(guān)技術(shù)背景有所了解。JAVA 作為一種成熟且廣泛應(yīng)用的編程語言,以其強(qiáng)大的跨平臺特性、豐富的類庫和良好的性能,為處理各種復(fù)雜任務(wù)提供了堅(jiān)實(shí)基礎(chǔ)。而 GDAL(Geospatial Data Abstraction Library)則是一個開源的地理空間數(shù)據(jù)抽象庫,它支持多種地理空間數(shù)據(jù)格式的讀寫操作,包括 S57 海圖文件。將 JAVA 與 GDAL 結(jié)合,能夠充分發(fā)揮兩者的優(yōu)勢,實(shí)現(xiàn)對 S57 海圖文件的高效解析。通過本次實(shí)戰(zhàn),我們將逐步深入,從搭建開發(fā)環(huán)境、配置相關(guān)依賴,到編寫代碼實(shí)現(xiàn)對 S57 海圖文件的讀取、解析以及數(shù)據(jù)提取等操作,全方位展示整個過程,讓讀者能夠清晰地掌握每個環(huán)節(jié)的關(guān)鍵點(diǎn)。
這場實(shí)戰(zhàn)不僅僅是對技術(shù)的實(shí)踐應(yīng)用,更是一次對地理空間數(shù)據(jù)處理領(lǐng)域的深入探索。在解析 S57 海圖文件的過程中,我們會遇到各種數(shù)據(jù)結(jié)構(gòu)、編碼方式以及地理空間概念等問題,通過解決這些問題,我們能夠更好地理解地理空間數(shù)據(jù)的內(nèi)在邏輯和處理方法。此外,本次實(shí)戰(zhàn)也將分享一些常見問題的解決方案和優(yōu)化技巧,幫助讀者在實(shí)際開發(fā)中避免遇到類似的困境。無論你是地理信息系統(tǒng)領(lǐng)域的開發(fā)者,還是對地理空間數(shù)據(jù)處理感興趣的程序員,相信通過本文的介紹,你都將收獲滿滿,為今后在相關(guān)領(lǐng)域的項(xiàng)目開發(fā)和個人學(xué)習(xí)奠定堅(jiān)實(shí)的基礎(chǔ)。
一、海圖文件簡介
為了讓大家對海圖文件有一個簡單的了解,本節(jié)將對海圖文件進(jìn)行一個簡單的介紹。由于之前也沒有接觸過海圖文件,因此也是自己的學(xué)習(xí)過程。信息記錄比較簡單,在以后的學(xué)習(xí)中不斷補(bǔ)充完善。首先給大家介紹依稀海圖文件是什么?然后以S57為例具體介紹海圖文件的文件類型。
1、什么是海圖文件
海圖文件是一種用于表示海洋地理信息的數(shù)字文件格式,它包含了海洋地形、水深、航行障礙物、海岸線、航標(biāo)等重要地理信息。這些信息對于航海安全、海洋資源開發(fā)、海洋科學(xué)研究以及軍事應(yīng)用等領(lǐng)域至關(guān)重要。海圖文件通常以矢量或柵格數(shù)據(jù)的形式存儲,能夠?yàn)榇皩?dǎo)航系統(tǒng)、地理信息系統(tǒng)(GIS)以及相關(guān)海洋應(yīng)用提供基礎(chǔ)數(shù)據(jù)支持。
2、S57海圖文件
S57 海圖文件是一種國際標(biāo)準(zhǔn)化的矢量海圖數(shù)據(jù)格式,由國際水道測量組織(IHO)制定并廣泛應(yīng)用于全球海洋領(lǐng)域。S57 文件格式具有以下特點(diǎn):
- 標(biāo)準(zhǔn)化:S57 格式遵循 IHO 的 S-57 標(biāo)準(zhǔn),確保了不同國家和地區(qū)之間的海圖數(shù)據(jù)可以無縫交換和互操作。
- 矢量數(shù)據(jù):S57 文件以矢量形式存儲地理信息,包括點(diǎn)、線、面等幾何對象,能夠提供高精度的地理數(shù)據(jù)表示。
- 豐富的屬性信息:除了幾何數(shù)據(jù)外,S57 文件還包含了大量的屬性信息,如水深、地形類型、航行警告等,這些屬性信息為用戶提供了更全面的海洋地理信息。
- 分層存儲:S57 文件支持分層存儲,用戶可以根據(jù)需要選擇顯示或處理特定的圖層,提高了數(shù)據(jù)處理的靈活性和效率。
- 兼容性:S57 文件格式被廣泛應(yīng)用于各種航海設(shè)備和地理信息系統(tǒng)軟件中,具有良好的兼容性。
S57 海圖文件的這些特點(diǎn)使其成為海洋地理信息領(lǐng)域的重要數(shù)據(jù)格式之一。通過解析 S57 文件,開發(fā)者可以提取出豐富的地理信息,用于開發(fā)各種海洋應(yīng)用,如船舶導(dǎo)航系統(tǒng)、海洋環(huán)境監(jiān)測、海洋資源管理等。
二、QGIS讀取S57實(shí)現(xiàn)
在了解了S57海圖文件后,接下來以QGIS為例,來看看海圖文件展示出來是什么樣子。從圖層信息和屬性信息查看兩個方面進(jìn)行介紹。
1、圖層展示
為演示海圖文件的加載,從C站獲取網(wǎng)友提供的海圖文件。下載后得到的S57海圖信息如下:

然后在QGIS中打開這些文件,與shp文件不一樣。海圖文件通常包含51個圖層,以C1313100.000這個文件為例。使用QGIS打開后可以看到有以下提示:

點(diǎn)擊“OK”按鈕將圖層添加到圖層組中,如下圖所示:

在Qgis的左邊可以看到所有的圖層信息,我們可以打開任意的一個圖層文件查看文件信息。如下圖所示:

2、屬性查看
圖層信息比較多,這里我們不一一的對其進(jìn)行查看。跟shp文件一樣,我們來看看其屬性信息都包含哪些呢?在Qgis中我們先來看看圖層有哪些屬性。在信息中可以看到以下信息:

可以看到這個圖層大約有30個字段。再來看看屬性表中這些信息度包含哪些內(nèi)容。

這些數(shù)據(jù)跟我們常用的數(shù)據(jù)庫類似,都是一條一條的記錄。
三、GDAL讀取S57實(shí)現(xiàn)
除了可以使用Qgis來打開讀取S57文件,我們還可以使用GDAL來進(jìn)行海圖文件的讀取。目前很多對海圖文件的讀取都是C或者C++為主,還有Python的。但是介紹Java的讀取的不多,因此本文也算是一個簡單的補(bǔ)充。對廣大的Java GIS 開發(fā)這有一個參考。
1、Maven引用
這里使用一種比較簡單的方式引入GDAL的jar,需要注意的是,在Java中要提前配置好GDAL的環(huán)境才可以,關(guān)于GDAL的java環(huán)境配置,可以翻閱之前的博客,有詳細(xì)的介紹。這里貼出jar引用代碼:
<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的第一次試驗(yàn)</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讀取
為了實(shí)現(xiàn)Java調(diào)用GDAL實(shí)現(xiàn)S57文件的讀取,我們首先來看看應(yīng)該調(diào)用什么驅(qū)動來進(jìn)行讀取。首先看看GDAL官網(wǎng)有沒有提供相關(guān)說明:

在官網(wǎng)上可以看到有對應(yīng)的驅(qū)動,點(diǎn)開S57后,可以看到以下的描述:

在GDAL中要實(shí)現(xiàn)S57文件的讀取的驅(qū)動使用“S57”即可。下面給出具體的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";
// 注冊所有的驅(qū)動
ogr.RegisterAll();
// 為了支持中文路徑,請?zhí)砑酉旅孢@句代碼
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
// 為了使屬性表字段支持中文,請?zhí)砑酉旅孢@句
gdal.SetConfigOption("SHAPE_ENCODING", "CP936");
// 讀取數(shù)據(jù),這里以ESRI的shp文件為例
String strDriverName = "S57";
// 創(chuàng)建一個文件,根據(jù)strDriverName擴(kuò)展名自動判斷驅(qū)動類型
org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
if (oDriver == null) {
System.out.println(strDriverName + " 驅(qū)動不可用!\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 ? "空" : "空間參考坐標(biāo)系:" + 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("數(shù)據(jù)量大小==>" + 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("總圖層數(shù):" + totalCount);
dataSource.delete();
gdal.GDALDestroyDriverManager();
}
}可以看到,對S57海圖文件的解析與shp文件的解析基本一致。讀取layer,然后就獲取feature,獲取屬性解析輸出即可。
3、讀取成果輸出
最后來看看使用Java調(diào)用GDAL對S57文件進(jìn)行解析后的屬性和空間信息,在控制臺輸出如下:

圖層名稱:<==>C_AGGR 空 - 數(shù)據(jù)量大小==>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=; ---------------------------------------------------
四、總結(jié)
以上就是本文的主要內(nèi)容,本次實(shí)戰(zhàn),我們將逐步深入,從搭建開發(fā)環(huán)境、配置相關(guān)依賴,到編寫代碼實(shí)現(xiàn)對 S57 海圖文件的讀取、解析以及數(shù)據(jù)提取等操作,全方位展示整個過程,讓讀者能夠清晰地掌握每個環(huán)節(jié)的關(guān)鍵點(diǎn)。這場實(shí)戰(zhàn)不僅僅是對技術(shù)的實(shí)踐應(yīng)用,更是一次對地理空間數(shù)據(jù)處理領(lǐng)域的深入探索。海圖文件繁多,可以做很多深入的研究,受限文章篇幅,這里不進(jìn)行贅述。拋磚引玉,大家可以對功能進(jìn)行擴(kuò)展。行文倉促,定有不足之處,歡迎各位朋友在評論區(qū)批評指正,不勝感激。
以上就是JAVA使用GDAL解析S57海圖文件全面詳解的詳細(xì)內(nèi)容,更多關(guān)于JAVA解析海圖文件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot整合quartz定時任務(wù)框架的完整步驟
在做項(xiàng)目時有時候會有定時器任務(wù)的功能,比如某某時間應(yīng)該做什么,多少秒應(yīng)該怎么樣之類的,下面這篇文章主要給大家介紹了關(guān)于springboot整合quartz定時任務(wù)框架的相關(guān)資料,需要的朋友可以參考下2022-01-01
Java mutable對象和immutable對象的區(qū)別說明
這篇文章主要介紹了Java mutable對象和immutable對象的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
詳解SpringMVC加載配置Properties文件的幾種方式
這篇文章主要介紹了詳解SpringMVC加載配置Properties文件的幾種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-02-02
Java.lang.NullPointerException的錯誤解決
Java中NullPointerException是一種常見的運(yùn)行時異常,通常發(fā)生在嘗試調(diào)用null對象的方法或訪問其屬性時,具有一定的參考價值,感興趣的可以了解一下2024-09-09
使用JVMTI實(shí)現(xiàn)SpringBoot的jar加密,防止反編譯
這篇文章主要介紹了使用JVMTI實(shí)現(xiàn)SpringBoot的jar加密,防止反編譯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
Spring Boot項(xiàng)目利用Redis實(shí)現(xiàn)session管理實(shí)例
本篇文章主要介紹了Spring Boot項(xiàng)目利用Redis實(shí)現(xiàn)session管理實(shí)例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
教你使用IDEA搭建spring源碼閱讀環(huán)境的詳細(xì)步驟
這篇文章主要介紹了使用IDEA搭建spring源碼閱讀環(huán)境的詳細(xì)步驟,本文分兩步通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-08-08

