Shapefile文件读取-文件头

1 介绍

Shapefile文件格式介绍一文中我们介绍了shapefile文件的结构组成,本文主要介绍如何读取shapefile文件头部分,使用的语言是c++。

2 文件头结构

Shapefile文件的文件头是固定长度的,总长度为100个字节,其中4-23字节为未使用部分,其他字段分别描述着当前shapefile文件的各类信息,在编码过程中,我们需要注意文件头中各字段的字节顺序以及类型,特别是File Length字段,这个是16位字表示的,在我们读取完成后需要转换成正常表示。

Bytes Field Value Type Byte Order
0-3 File Code 9994 Integer Big Endian
4-23 Unused 0 Integer Big Endian
24-27 File Length File Length Integer Big Endian
28-31 Version 1000 Integer Little Endian
32-35 Shape Type Shape Type Integer Little Endian
36-67 Minimum Bounding Rectangle Xmin, Ymin, Xmax and Ymax double Little Endian
68-83 Bounding Box Zmin, Zmax double Little Endian
84-99 Bounding Box Mmin, Mmax double Little Endian

3 数据结构封装

因为文件头是固定长度的,所以我们可以封装一个文件头数据结构,然后直接从文件中读取100个字节即可,另外文件头中还包含其他如Bounding box和shape type等结构,我们一次封装即可。

3.1 Bounding Box

Bounding box主要用来表示几何形状边界信息,在文件头中主要是36-99字节使用,由若干double组成,为了后续使用方便,我们封装两种不同类型的Bounding Box结构,具体如下:

class bounding_box4
{
public:
	double x1;
	double y1;
	double x2;
	double y2;
};

class bounding_box2
{
public:
	double x;
	double y;
};

3.2 Shape type

shape type字段主要是用来表示当前文件所描述的几何类型,在文件头中用一个int表示,下面是所有的shape type不同值所表示的几何类型。

Value Shape Type
0 Null Shape
1 Point
3 Polyline
5 Polygon
8 MultiPoint
11 PointZ
13 PolyLineZ
15 PolygonZ
18 MultiPointZ
21 PointM
23 PolyLineM
25 PolygonM
28 MultiPointM
31 MultiPatch

我们可以用enum class来封装所有的shape type值。

enum class ShapeType
{
	ST_NULL = 0,
	ST_POINT = 1,
	ST_POLYLINE = 3,
	ST_POLYGON = 5,
	ST_MULTI_POINT = 8,
	ST_POINT_Z = 11,
	ST_POLYLINE_Z = 13,
	ST_POLYGON_Z = 15,
	ST_MULTI_POINT_Z = 18,
	ST_POINT_M = 21,
	ST_POLYLINE_M = 23,
	ST_POLYGON_M = 25,
	ST_MULTI_POINT_M = 28,
	ST_MULTI_PATCH = 31,
};

3.3 ShapeFileHeader

我们用ShapeFileHeader类来表示整个文件头部分,这里需要注意文件头中有int和double数据类型,要注意字节对齐引入的整个文件头大小变化问题,这里我们使用pack指令强制4字节对齐,具体如下:

#pragma pack(4)
class ShapeFileHeader
{
public:
	int file_code;
	char reversed[20];
	int file_length;
	int version;
	ShapeType shape_type;
	bounding_box4 xy_bounding;
	bounding_box2 z_boudning;
	bounding_box2 m_boundnig;
};
#pragma pack()

3.4 大小端转换

因为文件头中的有些字段是用大端模式表示的,所以这里我们添加一个转换方法:

void inline swap_bytes32(unsigned int &val)
{
	val = (val >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0xff00) << 8) | (val << 24);
}

测试代码

#include <iostream>
#include <fstream>

using namespace std;

class bounding_box4
{
public:
	double x1;
	double y1;
	double x2;
	double y2;
};

class bounding_box2
{
public:
	double x;
	double y;
};

enum class ShapeType
{
	ST_NULL = 0,
	ST_POINT = 1,
	ST_POLYLINE = 3,
	ST_POLYGON = 5,
	ST_MULTI_POINT = 8,
	ST_POINT_Z = 11,
	ST_POLYLINE_Z = 13,
	ST_POLYGON_Z = 15,
	ST_MULTI_POINT_Z = 18,
	ST_POINT_M = 21,
	ST_POLYLINE_M = 23,
	ST_POLYGON_M = 25,
	ST_MULTI_POINT_M = 28,
	ST_MULTI_PATCH = 31,
};

#pragma pack(4)
class ShapeFileHeader
{
public:
	unsigned int file_code;
	char reversed[20];
	unsigned int file_length;
	unsigned int version;
	ShapeType shape_type;
	bounding_box4 xy_bounding;
	bounding_box2 z_boudning;
	bounding_box2 m_boundnig;
};
#pragma pack()

void inline swap_bytes32(unsigned int& val)
{
	val = (val >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0xff00) << 8) | (val << 24);
}

int main(int argc, char* argv[])
{
	string file_path = "C:\\Users\\Administrator\\Downloads\\AM_RunwayElement.shp";
	ShapeFileHeader header;
	ifstream in(file_path, ifstream::binary);

	in.read((char*)&header, sizeof(header));

	swap_bytes32(header.file_code);
	swap_bytes32(header.file_length);

	// get actual file length
	header.file_length *= 2;

	cout << header.file_code << endl;
	cout << header.version << endl;

	in.close();
}
上一篇:【经典论文解读】YOLOv2 目标检测


下一篇:AABB包围盒和OBB包围盒区别