0引言
电子海图以海域要素为主,其内容相当丰富,可详细表示海底地形(水深)、航行障碍物、助航标志、港口设施、潮流、海流等要素,甚至连磁力异常区域、灯塔、浮标都被包含在内。随着导航计算机的使用,电子海图已经逐渐取代纸质海图,作为舰船航行的导航工具。尤其是水下航行器的远程精确导航,将完全依赖于信息丰富的电子海图,应用系统将向着航线自主规划、跟踪动态目标制定航行计划等智能化方向发展。虽然S-57矢量电子海图具有信息丰富、可无限放大及存储占用空间小等优点,可被使用于水面舰船或者水下航行器中,但其封装结构是一种高压缩的数据交换格式,是用户不可见的.000数据格式,且数据结构较为复杂。要将电子海图应用到水下航行器等特殊领域,前提是要能实时对其快速解包。
1电子海图分类
电子海图主要分为两大类:栅格式电子海图和矢量电子海图。由于矢量格式电子海图具有存储占用内存空间小、加载速度快等特点,更容易实现各种智能化功能,本文选用国际标准S-57电子海图数据文件作为数据提取识别对象,分类及特点如图1所示
2电子海图封装结构及数据模型
为方便、快捷地进行数据文件交换,S-57标准对现实世界的各类水文实体进行模型归纳抽象,定义适当的数据结构(抽象模型的数学实例化)及文件的物理封装。S-57格式的电子海图原始数据按照ISO/ICE8211进行数据封装,它是一种能够在不同类型计算机之间进行数据交换的交换格式。该结构可基于文件机制从一种计算机体系向另一种计算机体系传递信息,提供独立于机器构造的格式。
ISO8211文件是以逻辑记录(LogicalRecord,LR)为基本单元组成。其第1个记录叫做数据描述记录(DataDeiveRecord,DDR)[3],其中主要包含海图的逻辑结构和具体数据描述,用于解析文件。其他逻辑记录叫做数据记录(DataRecord,DR),存储的是实际的海图数据值。ISO8211封装结构如图2所示。每个逻辑记录由头标区、目录区、字段组成。海图数据解包就是要将海图中各个逻辑记录的三大类基本信息都读取出来。
S-57采用链-节点的数据拓扑结构,现实世界被抽象为特征物标和空间物标两大类。特征物标用来描述事物的特征属性,空间物标则描述其空间属性。特征物标仅包含事物的特征属性,并不包括任何几何形状和坐标位置信息。特征物标又分为元物标、集合物标、地理物标和制图物标四大类。
空间物标可以包含位置信息,必包含几何形状,分为点、边、面3种。S-57标准数学抽象模型如图3所示。
S-57制定了电子海图数据的数据结构,也就是在计算机内存储的物理结构。海图数据记录的形成意味着从逻辑结构向物理结构的成功转换。数据包含特征记录、数据集描述记录、目录记录、数据字典记录、和空间记录等5类记录。其中数据字典记录较少使用。
S-57海图将沿海、港口及大洋等现实世界逐步抽象,构成物理交换格式,其抽象过程如图4所示。各抽象层之间的关系如图5所示。
根据其表示真实世界的模型及其交换数据的封装标准,对原始数据一层层地进行解包,实质上就是数据模型抽象的逆过程。
3电子海图解包
S-57电子海图解包就是按照其封装标准将矢量海图数据各字段和子字段逐一读取出来。针对适用于水下航行器的数据,主要读取的字段包括:特征物标标识字段(FOID)、特征记录标识字段(FRID)、特征记录到物标指针字段(FFPT)、特征记录到空间记录指针字段FSPT(包含NAME指针)、矢量记录参数字段(VRID)、矢量一记录指针字段(VRPT)、二维坐标字段SG2D(包含所有点的经纬度坐标)及三维坐标字段SG3D(包含水深点经纬坐标及水深值)。
本文利用处理ISO8211lib开源库中包含五个类,实现快速解读格式为.000的S-57原始电子海图数据。
数据描述模型类(Datadeionfield,DDFModule)是ISO8211lib其中最主要的一类,用于从.000文件中以记录为单位读取记录信息,包含全部从DDR读取的信息。在开始读取S-57文件之前,首先必须建立一个数据描述模型类对象,然后调用Open()函数,若调用成功,所有的字段和子字段就可以被使用。
数据描述模型类的成员函数ReadRecord():只是1次读1个记录,下次读取的时候需要重写。整个读取过程都以记录为单位,每次读取1个记录,再读取记录里包含的字段及子字段,依次层层往下读取。当1个记录读取完成后,又需要获得新的记录指针值,用于读取下1个记录。
数据描述记录类(DDFRecord类):包含从DR读取的实例化数据,其中包含1个记录里所有的DDFField字段数据。通过该类成员函数Getfield(i)函数,得到1个按照索引地址把值传递给指向数据描述字段类的指针,传递1次,i值减加1,当i的值等位于0和GetFieldCount()-1之间,循环结束时,即完成本记录的全部扫描。
数据描述字段类(DDFField类):从数据描述记录类的GetFieldDefn()函数得到的1个实例化的指向数据描述子字段类的Field指针。利用该类的成员函数GetRepeatCount()可得到所需要读取字段的重复个数,利用该重复个数,可以控制读取重复字段时循环次数。
数据描述子字段类(DDFFieldDefn类):通常作为提取子字段数据类的容器。该类成员函数GetName()用于读取所读当前字段的名称。GetSu-bfieldCount()成员函数可返回读取字段的子字段个数,以控制读取子字段的循环次数。
提取子字段数据类(DDFSubFieldDefn类):是提取海图数据最里层的1个类,用于提取具体的1个子字段的信息。成员函数GetType()用来获取子字段的数据类型,从而对应调用读取整形数据、浮点型数据或者字符串型数据的成员函数。
根据海图的封装结构,利用上述5个开源类,逐个实现类的实例化,从而层层读取S-57电子海图文件的全部数据。类调用的先后顺序如图6所示,读取数据流程图如图7和图8所示。读取的原则遵循层层剥开,最终到达子字段内容,读1条存1条,读完1条迅速释放内存,再建立类对象,读取下1条记录,该方式不占用内存资源且CPU开销较小。
读取过程如下:
1)打开S-57格式电子海图.000文件,创建1个数据描述模型类对象Module,然后调用Open()函数,如果调用成功,进行下一步;
2)创建1个数据描述记录类指针*pointRecord,调用Module.ReadRecord(),将返回值传给类指针*pointRecord;
3)调用pointRecord->GetField()函数,将返回值传给数据描述字段类指针*pointField,进行实例化;
4)调用pointField->GetFieldDefn(),返回值传给数据描述子字段类实例化*pointFieldDefn指针;
5)通过调用pointFieldDefn->GetName()和pointFieldDefn->GetDescritpion()两个函数,读取字段的名称和数据;
6)调用pointField->GetSubfield(),将返回值传给提取子字段数据类实例化*poSFDefn指针,进行实例化;
7)调用poSFDefn->ExtraetData(),读取poSFDefn的数据。
读取流程如图7和图8所示
4数据可视化存储及试验
在VisualStdio2008环境下,建立1个MFC单文档工程,并添加1个删除数据按钮。利用MFC的工具栏打开按键,编程实现打开.000标准电子海图文件。并在view界面中添加删除数据按钮,用于删除解包后的电子海图文件。
所有的函数调用及类的调用实现程序都编写在doc.cpp文件中。按照解包算法读取文件。海图数据快速解包后,为方便后续的电子海图数据的研究运用及其开发,需要将数据可视化的存储。就是基本按照其封装架构不动,将读取出来的数据以记录为单位,读1条存1条。读出的文件全部存储于CString类型的变量中,并且进行格式化后,依次存储于txt文件中。
在实现电子海图数据可视化之后,可以方便地查看各字段数据,为电子海图更为专用的设计应用提供可查可验证的数据。
经验证,S-57电子海图文件USSMD12M.000已经被读取并存储。读取后存储的DSID字段及DSSI字段如图9所示。矢量记录SG2D字段如图10所示。并且每个字段后面都读出了字段描述信息,从而实现每个子字段信息都成功读出并存储。
5结语
电子海图包含了丰富的海洋信息,使用这些信息的前提是能够正确快速地读取海图数据。过去电子海图主要用于水面船只人工航行规划,所用信息不多。而本文将S-57标准电子海图进行快速读取并以记录为单位存储下来,为今后进行将电子海图应用于水下航行器提供了基础。根据电子海图的一些特殊应用背景,利用读取的海图数据可以进行海图要素裁剪及存储结构的优化,可构建面向水下航行器专用的数据模型。根据海图原始数据模型存储海图矢量数据,层层读取并存储各字段数据,既不影响海图数据的原有结构,又不丢失海图的原有信息,是海图矢量数据应用的关键和前提。在实现完全读取电子海图数据后,能够为水下航行器的航路规划提供输入。