1. .shp文件简介
shp
文件是ESRI
(美国环境系统研究所公司)开发的一种用于存储和描述空间数据的文件格式(shapefile),目前已经成为GIS中的开放标准。shp
常用来描述基本几何对象:点、线、多边形。(shapefile其实也可以存储对象的各种人为定义的属性,但那些属性数据是存放在dBase File(dbf)
中的,不属于本文的内容。)
ArcMap
中这样描述:
Shapefile 是一种用于存储地理要素的几何位置和属性信息的非拓扑简单格式。 shapefile 中的地理要素可表示为点、线或面(区域)。 包含 shapefile 的工作空间还可以包含 dBASE 表,它们用于存储可连接到 shapefile 的要素的附加属性。
笔者
这样理解shape文件:
一种可扩展的、用于存储基本几何对象的、可描述基本地理信息的二进制文件格式。
shp
文件的读写,源代码(openfile仓库的shp文件夹中)在github上,有兴趣的同学可以自取,如对代码有任何疑问,欢迎提交issue
,或者添加笔者QQ:3495421705
。同时也欢迎各位同学加入到该仓库的建设和维护中。
注意,在本文中,只讨论shp
文件这一个文件格式相关内容,关于shx
和dbf
这两个文件格式,将会在后续文章中介绍。
2. shp文件格式
shp
文件格式比较简单,分为文件头
和记录列表
两块。
2.1 文件头
shp
文件头是一个定长100字节
的数据块,其中的内容由以下部分组成:
字段名 | 数据长度(字节) | 字节序 | 备注 |
---|---|---|---|
文件码(file code) | sizeof(int32) = 4 | big | |
未使用 | 5 * sizeof(int32) = 20 | big | |
文件长度(File Length) | sizeof(int32) = 4 | big | |
文件版本(version) | sizeof(int32) = 4 | little | |
图元类型(shape type) | sizeof(int32)=4 | little | |
xy数据范围(包围盒) | 4 * sizeof(double) = 32 | little | 分别为xmin 、ymin 、xmax 、ymax |
z和m数据范围 | 4 * sizeof(double)=32 | little | 分别为:zmin 、zmax 、mmin 、mmax |
上表中关于字节序
的知识,大家可以上网搜索,其原理就是不同系统要求的数据在内存中的字节顺序不一样,其中:
BigEndian
机器上,0x0102
在内存中的字节顺序为0x01
和0x02
,但是在LittleEndian
的机器上,他的字节顺序就变成了0x02
和0x01
。
字节转换的工具函数,在shp
读写的源码仓库中已有实现。
2.2 文件记录
shp
的文件记录,是变长
的,根据其内部存储的数据量而定。shp
文件并没有记录
一说,从概念上来看,其每一个shape
实际上都可以看成列表中的一条记录,因此被称为记录
。
shp
中的每一条记录,都可以被分为两个部分:记录描述字段
和shape数据
。
- 记录描述字段
用来描述当前记录的基本信息:记录编号、记录长度(字节
)。- shape数据
图元的顶点及分段。
shp
的 图元类型(ShapeType) 总共有13种:点(Z、M)
、多点(Z、M)
、折线(Z、M)
、多边形(Z、M)
、片元(Patch)
。其中,Z
代表含有z
坐标值的图元,M
表示含有量测(Measurement)
值的图元。图元类型 在shape规范中对应的值如下:
enum ShapeType
{
kNullShape = 0,
kPoint = 1,
kPolyLine = 3,
kPolygon = 5,
kMultiPoint = 8,
kPointZ = 11,
kPolyLineZ = 13,
kPolygonZ = 15,
kMultiPointZ = 18,
kPointM = 21,
kPolyLineM = 23,
kPolygonM = 25,
kMultiPointM = 28,
kMultiPatch = 31
};
在shape数据记录中,记录描述可以做如下定义:
struct RecordField
{
int32_t recordNumber; // big
int32_t contentLength; // big
int32_t shapeType; // little
};
其中,RecordNumber
是记录编号,ContentLength
是当前图元的数据长度(字节),ShapeType
是当前记录的图元类型。在shapefile的规范文件中,ShapeType
是与记录描述分开的,但笔者认为,可以将ShapeType放到记录描述字段结构体中。
在ShapeType
之后,就是图元的真实数据,根据下表,可以查询每种图元的数据内容:
图元类型 | 数据内容 | 备注 |
---|---|---|
Point | double[X,Y] | |
PointM | double[X,Y,M] | |
PointZ | double[X,Y,Z,M] | |
MultiPoint | double[4] Box int32 NumPoints Points[NumPoints] Points | 包围盒 点数 顶点数组 |
MultiPointM | double[4] Box int32 NumPoints Points[NumPoints] Points double[2] MRange double[NumPoints] M Array | 包围盒 点数 顶点数组 M数据范围 M值数组 |
MultiPointZ | double[4] Box int32 NumPoints Points[NumPoints] Points double[2] MRange double[NumPoints] M Array double[2] Z Range double[NumPoints] Z Array | 包围盒 点数 顶点数组 M数据范围 M值数组 Z值范围 Z值数组 |
Polyline | double[4] Box int32 NumParts int32 NumPoints int32[NumParts] Parts Points[NumPoints] Points | 包围盒 段数 点数 段索引数组 顶点数组 |
PolylineM | double[4] Box int32 NumParts int32 NumPoints int32[NumParts] Parts Points[NumPoints] Points double[2] MRange double[NumPoints] M Array | 包围盒 段数 点数 段索引数组 顶点数组 M数据范围 M值数组 |
PolylineZ | double[4] Box int32 NumParts int32 NumPoints int32[NumParts] Parts Points[NumPoints] Points double[2] MRange double[NumPoints] M Array double[2] Z Range double[NumPoints] Z Array | 包围盒 段数 点数 段索引数组 顶点数组 M数据范围 M值数组 Z值范围 Z值数组 |
Polygon
和Polyline
的数据内容一样,同理Z
和M
类型也一样。不一样的是,多边形和折线对**段(Parts)**的解释不一样。
2.3 多边形的段(Part)
Polygon
在shapefile中有一些需要 注意 的点:
- 多边形的
环(Ring)
是闭合的:第一个顶点和最后一个顶点必须一样;- 环在多边形顶点数组的顺序并不重要。
- 多边形必须是
干净
的,干净
的含义是:
a. 无自相交;
b. 多边形的顶点顺序是顺时针
方向的,顺时针的右边为多边形内部。这也是第2
点的原因;
多边形的段,每一段的最后一个顶点,和该段的第一个顶点坐标是一样的,这符合上面的第1
点,也是多边形和折线的最大不同之处。有了以上基本信息之后,shp
文件的读写就很简单了。
3. shp文件读写——C++
shp
文件读写的C++实现已经在前文提到的github仓库中了,这里再次给出github链接:openfile.shp。
3.1 仓库简介
openfile
是一个自包含
、无外部依赖
的文件读写工具集,这些文件包含大部分常见的文件格式,包括但不限于:
栅格数据
:tiff、geotiff、img等;
矢量数据
:shp(shx和dbf)、dxf等;
点云数据
:las(laz)、xyz等;
文本数据
:json、xml等;
该工具集的目标如下:
- 自包含:一些常用工具已经自己实现;
- 无外部依赖:不依赖任何其他三方库,如png文件的读写,不依赖libpng;
- 模块化构建和使用:每种文件格式都与其他格式独立,需要什么格式,直接编译对应库即可;
- 跨平台:支持Windows、Linux、MacOS等;
- 一建构建编译:需要json,开启json模块编译选项,直接输出对应库;
openfile
在本文编写时,尚处于起步阶段,本文所介绍的shp
文件也是openfile
实现的第一个文件读写库。希望读者朋友们能够参与本仓库的开发和维护,一起为开源社区贡献力量。
3.1 代码结构简介
shp
读写库的公开接口只有以下5个:
- enum ShapeType:图元类型枚举;
- class shp:shp文件的操作类;
- class Shape:图元操作接口类;
- struct ShpHeader:shp文件头的结构体;
- 字节序转换函数;
在source/shp
中,则包含了以下内容:
- class ShpInternal:shp类的内部接口类,被读写器类内部依赖;
- class Reader:shp文件的读工具类;
- class Writer:shp文件的写工具类;
- class ShpRecord:shp文件记录类,负责管理和操作
记录描述结构体
和图元
;- impl/xxx.hpp:图元的具体实现类
4 结语
openfile
的QQ交流群已经建好,有兴趣的同学可以加入一起交流:157588707
,也可以扫下面二维码加入: