shp系列(二)——利用C++进行shp文件的读(打开)
发布日期:2022-02-10 11:37:02 浏览次数:46 分类:技术文章

本文共 6309 字,大约阅读时间需要 21 分钟。

1.各数据类型及其字节数

BYTE 1;       char 1;    short 2;      int 4;    double 8;

2.位序big和little及其转换

对于位序是big的数据我们在读取时要小心。通常,数据的位序都是Little,但在有些情况下可能会是big,二者的区别在于它们位序的顺序相反。一个位序为big的数据,如果我们想得到它的真实数值,需要将它的位序转换成Little即可。转换原理就是交换字节顺序,下面是转换代码(big->little):

int OnChangeByteOrder(int indata){	char ss[9];	char ee[8];	unsigned long val = unsigned long(indata);	ultoa(val, ss, 16);// 将十六进制的数(val)转到一个字符串(ss)中,itoa(val,ss,16);  	int i;	int length = strlen(ss);	if (length != 8){		for (i = 0; i<8 - length; i++)			ee[i] = '0';		for (i = 0; i

3.shp文件的基本构成

shp文件,由于包含最主要的数据坐标数据,也叫主文件、坐标文件,由文件头和实体信息构成:

文件头是关于主文件的基本描述,包括版本号、文件长度等信息;实体信息是每一个图形的具体信息,也包括记录头和坐标内容。

4.shp头文件

头文件的结构如下,下面两表含义相同。

有值得说明的几点:

  • 前9项都是int类型,位序是big;后8项都是double类型,位序是little,所以头文件的大小为  9 * 4 + 8 * 8 = 100。
  • FileCode固定为9994,Version固定为1000。
  • FileLength是指总文件长度,大小为  :头文件长度 + (记录头长度 + 记录内容长度) * 记录数
  • ShapeType为该shp文件图形的类型(1代表Point,3代表Polyline,5代表Polygon),更多的类型参考说明文件,目前每个 shape 文件被限定为只能包含上述类型的一种。
  • Xmin,Ymin,Xmax,Ymax是空间范围的边界。
  • Zmin,Zmax,Mmin,Mmax一般用不到。

5.shp实体信息

shp实体信息分为记录头和记录内容。

5.1记录头

每个记录的记录头都储存着记录号(Record Number)和记录内容长度(Content Length)位序都是big,类型是int,记录头的长度是 8 个字节,记录号从 1 开始。

  • RecordNumber代表当前记录的编号。
  • ContentLength代表当前记录内容的长度,不包括RecordNumber和ContentLength本身的长度,下面将以面状要素为例计算ContentLength的大小。

5.2记录内容

不同的要素类型的记录内容不一样,本次以面状要素为例(Polygon,ShapeType为5),面状要素的记录内容如下:

  • ShapeType是指多边形的类型,Polygon是5。
  • Box是double类型的数组,包含多边形的4个边界。
  • NumParts代表Polygon的子环数,一个Polygon可能由多个环。
  • Parts是一个int类型数组,数组元素个数等于NumParts,每个元素记录了每个子环的坐标在Points数组中的起始位置。
  • Points记录Polygon的所有点,是Point类型,Point类型包含2个double类型(x,y均为double)。

所以一条记录(Polygon)的ContentLength(字节数)大小为:

4 + 4 * 8 + 4 + 4 + NumParts * 4 + NumPoints * 2 * 8 ,不包括RecordNumber和ContentLength本身的长度,ContentLength实际值为字节数的一半,后面FileLength也是字节数的一半。所以ContentLength = ContentLength/2。

 

6.shp读取的C++函数代码:

void readShp(void){	//****打开坐标文件 	CFileDialog fDLG(true);	if (fDLG.DoModal() != IDOK)		return;	filename = fDLG.GetPathName();	FILE* m_ShpFile_fp = fopen(filename, "rb");	if (m_ShpFile_fp == NULL) {		MessageBox("Open File Failed");		exit(0);	}	CGeoMap* map = new CGeoMap();      //创建地图对象	CGeoLayer* layer = new CGeoLayer();//新建图层						   	//****定义读取坐标文件头的变量 	int i;	int FileCode = -1;	int Unused = -1;	int FileLength = -1;	int Version = -1;	int ShapeType = -1;	double Xmin;	double Ymin;	double Xmax;	double Ymax;	double Zmin;	double Zmax;	double Mmin;	double Mmax;	//****读取坐标头文件	fread(&FileCode, sizeof(int), 1, m_ShpFile_fp);  //从m_ShpFile_fp里面的值读到Filecode里面去,每次读一个int型字节的长度,读取一次  	FileCode = OnChangeByteOrder(FileCode);          //将读取的FileCode的值转化为十进制的数  	for (i = 0; i<5; i++)		fread(&Unused, sizeof(int), 1, m_ShpFile_fp);	fread(&FileLength, sizeof(int), 1, m_ShpFile_fp);//读取FileLength  	FileLength = OnChangeByteOrder(FileLength);      //将FileLength转化为十进制的数  	fread(&Version, sizeof(int), 1, m_ShpFile_fp);   //读取Version的值  	fread(&ShapeType, sizeof(int), 1, m_ShpFile_fp);//读取ShapeType的值  	fread(&Xmin, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Xmin里面去,每次读取一个double型字节长度,读取一次  	fread(&Ymin, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Ymin里面去,每次读取一个double型字节长度,读取一次  	fread(&Xmax, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Xmax里面去,每次读取一个double型字节长度,读取一次  	fread(&Ymax, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Ymax里面去,每次读取一个double型字节长度,读取一次  	CRect rect(Xmin, Ymin, Xmax, Ymax);	layer->setRect(rect);                         //设置图层的边界	fread(&Zmin, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Zmin里面去,每次读取一个double型字节长度,读取一次  	fread(&Zmax, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Zmax里面去,每次读取一个double型字节长度,读取一次  	fread(&Mmin, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Mmin里面去,每次读取一个double型字节长度,读取一次  	fread(&Mmax, sizeof(double), 1, m_ShpFile_fp);//从m_ShpFile_fp里面的值读到Mmax里面去,每次读取一个double型字节长度,读取一次  	//****读取坐标文件头的内容结束	//****读取面状目标的实体信息	int RecordNumber;	int ContentLength;	switch (ShapeType) {	case 5: {  //polygon		while ((fread(&RecordNumber, sizeof(int), 1, m_ShpFile_fp) != 0)) { //从第一个开始循环读取每一个Polygon			fread(&ContentLength, sizeof(int), 1, m_ShpFile_fp);            //读取ContentLength			RecordNumber = OnChangeByteOrder(RecordNumber);                 //转换为10进制			ContentLength = OnChangeByteOrder(ContentLength);			//****记录头读取结束			//****读取记录内容			int shapeType;   //当前Polygon几何类型			double Box[4];   //当前Polygon的上下左右边界			int NumParts;    //当前Polygon所包含的子环的个数			int NumPoints;   //当前Polygon所包含的点的个数			int *Parts;      //当前Polygon所包含的子环的起点在NumPoints的编号			fread(&shapeType, sizeof(int), 1, m_ShpFile_fp);			for (i = 0; i < 4; i++)                         //读Box				fread(Box + i, sizeof(double), 1, m_ShpFile_fp);			fread(&NumParts, sizeof(int), 1, m_ShpFile_fp); //表示构成当前Polygon的子环的个数			fread(&NumPoints, sizeof(int), 1, m_ShpFile_fp);//表示构成当前Polygon所包含的坐标点个数			Parts = new int[NumParts];                      //记录了每个子环的坐标在Points数组中的起始位置			for (i = 0; i < NumParts; i++)				fread(Parts + i, sizeof(int), 1, m_ShpFile_fp);			int pointNum;			CGeoPolygon* polygon = new CGeoPolygon();			polygon->circleNum = NumParts;                   //设定多边形的点数			//****读取面中子环			for (i = 0; i < NumParts; i++) {  				if (i != NumParts - 1)  pointNum = Parts[i + 1] - Parts[i];//每个子环的长度 ,非最后一个环				else  pointNum = NumPoints - Parts[i];       //最后一个环				double* PointsX = new double[pointNum];      //用于存放读取的点坐标x值;				double* PointsY = new double[pointNum];      //用于存放y值				CGeoPolyline* polyline = new CGeoPolyline(); //每个环实际上就是首尾坐标相同的Polyline				polyline->circleID = i; 				for (int j = 0; j < pointNum; j++) {					fread(PointsX + j, sizeof(double), 1, m_ShpFile_fp);					fread(PointsY + j, sizeof(double), 1, m_ShpFile_fp);					double a = PointsX[j];					double b = PointsY[j];					CPoint* point = new CPoint(a, b);					polyline->AddPoint(point);               //把该子环所有的点添加到一条链上				}				CPoint pt1 = polyline->pts[0]->GetCPoint();				CPoint pt2 = polyline->pts[polyline->pts.size() - 1]->GetCPoint();				if (pt1 != pt2) {  //若首位点不一致					CString str;					str.Format("%d数据首尾点不一致", RecordNumber);					polyline->pts.push_back(p1);				}				polygon->AddCircle(polyline);                 //将polyline链添加到对应polygon中				delete[] PointsX;				delete[] PointsY;			}			//****一个面的某个子环循环结束,同时该子环已加入到polygon			 			layer->AddObject((CGeoObject*)polygon);           //将该polygon加入到图层中			delete[] Parts;		}		map->AddLayer(layer);	}		break;	case 1://point		break;	case 3://polyline		break;	default:		break;	}}

下一篇博客介绍dbf文件的读取。

转载地址:https://blog.csdn.net/Fan_z_0802/article/details/85121329 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:(四)建筑物多边形化简系统——“去尾巴”和分割复杂多边形
下一篇:shp系列(三)——利用C++进行DBF文件的读(打开)

发表评论

最新留言

不错!
[***.144.177.141]2024年03月02日 06时54分34秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

python分析彩票数据,这波太炸了!Python脚本可视化居然可以这么玩 2019-04-21
简单的mysql重置root密码,重置mysql的root密码最简单的方法 2019-04-21
用matlab仿真mmc环流抑制器,一种基于准PR控制原理的MMC阀组环流抑制方法 2019-04-21
oracle 排序的分析函数,Oracle SQL:使用分析排序函数 2019-04-21
oracle direct for hdfs xi下载,ORACLE连接HDFS有个专项的解决方案 2019-04-21
java 403怎么抛出_java – 如何在Spring MVC中返回403禁止? 2019-04-21
java jsch工具类_Java工具集-JSch连接远程服务器工具类 2019-04-21
cmd背景变红1003无标题_怎样修改cmd中文字的大小、颜色和背景颜色呢 原来是这样的... 2019-04-21
php rand() 重复,php – mt_rand()给我总是相同的数字 2019-04-21
php taglib.php,thinkphp5 taglib自定义标签教程 2019-04-21
java常用包类 array,Java中的StringBuffer和数组Arrays以及常用类型的包装类 2019-04-21
ctf常见php,CTF中常见的PHP伪协议 2019-04-21
php语言冒泡法,PHP 冒泡排序法 2019-04-21
php如何数组去重复,PHP如何去除数组重复元素? 2019-04-21
java转换ab的值,查看新闻/公告--[整理]Java将AB1234形式的16进制字符串转换为10进制数值,考虑字节序的影响.... 2019-04-21
ui php h5,画出自己的UI组件的详情 2019-04-21
linux服务文件编写,linux编写systemd下服务脚本 2019-04-21
hdfs linux 目录是否存在,Linux中判断hdfs文件是否存在 2019-04-21
linux学习需要什么基础,学linux需要什么基础? 2019-04-21
linux vim编辑kconfig 无法wq,Linux-4.9.2内核在mini2440上的移植(三)——编译环境测试... 2019-04-21