langqi1988的个人博客分享 http://blog.sciencenet.cn/u/langqi1988

博文

读取shape格式文档

已有 3262 次阅读 2013-8-1 17:08 |个人分类:technology|系统分类:科研笔记| 文档, shape

自己写了个读取shape格式的文档,希望各位专家指导

Shape 头文件结构分析

起止位置字段名称字段的值类型字节顺序

0-3 file code 9994 Integer

4-23 保留字 0 Integer

24-27 文件长度 Integer 高位

28-31 版本号 Integer

32-35 图形类型 Integer

36-43 Bunding Box Xmin Double

44-51 Bunding Box Ymin Double

52-59 Bunding Box Xmax Double

60-67 Bunding Box Ymax Double

接着是记录头信息,记录头信息和记录数据信息是循环的。每一条记录都包括记录头信息+记录数据信息。

记录的头信息是固定的长度,而记录数据信息根据不同的记录结构体的不同而变化。但是,每种结构体的结构是固定的。

Shape 记录条文头信息分析

主文件记录头的描述

Positoin Filed Value Type Oreder

0-3 记录编号 Integer Big

4-7 该记录的长度 Integer Big

Shape的数据记录条文内容是由 shape类型和shape的结构体数据组成。每一种shape类型,都是先描述,然后再把记录内容记录在磁盘上的。描述信息就是头信息包括的编号和长度。

下面以PolyLine 为例说明一下,数据存储结构。

Positoin Filed Value Type Oreder

0-3 记录编号 Integer Big

4-7 该记录的长度 Integer Big

8-11 类型ShapeType Value=3 Little

12-35 Box Bounding 4*Double Little

36-39 NumParts Integer Little

40-43 NumPoints Integer Little

44-47 Integer[Num]Parts Integer Little

ByteX-Y Integer[NumPoints]Points Integer Little

Note: X= 44+4*NumParts

Y= X+NumPoints*16(xy坐标都是一个double)

因此,解析一个完整的Shape文件。首先是解析头信息,获得重要的 Shape 类型,根据Shape类型来解析记录条文信息。数据都是以16进制记录,没有空格。

头信息占据前99个字节,

读取shape头文件信息(一下的读取是依次读取)

br.RedBytes(24);//头二十四个大部分是保留位。

intFileLength = br.ReadInt32();//<0代表数据长度未知

FileLength这里是高位需要转换一下。

intFileBanben = br.ReadInt32();

ShapeType = br.ReadInt32();

xmin = br.ReadDouble();

ymin = br.ReadDouble();

xmax = br.ReadDouble();

ymax = br.ReadDouble();

br.ReadBytes(32); --读取到99个字节,头信息读取完毕

ulongbig2little(int code) //将big位序转换为little位序

{

ulong value;

value = ((((ulong)(code) & (ulong)0x000000ffUL)<< 24) | (((ulong)(code) & (ulong)0x0000ff00UL) << 8) | (((ulong)(code) & (ulong)0x00ff0000UL)>> 8) | (((ulong)(code) & (ulong)0xff000000UL) >> 24));

returnvalue;

}

例如:读取头信息,需要高位转低位。

intRecordNum = br.ReadInt32();

RecordNum = Convert.ToInt32(big2little(RecordNum));

intDataLength = br.ReadInt32();

DataLength= Convert.ToInt32(big2little(DataLength));

头信息读取完毕了,接着就是根据shapeType 来读取接下来的存储的数据。

以读取线类型信息为例说明(一条完整的记录包括记录条文的头信息和多段线数据结构信息)

structPolyLine_shape // 使用该结构体来表示多段线的信息结构

{

publicdouble[] Box; //边界盒

publicintNumParts; //部分的数目

publicintNumPoints; //点的总数目

publicArrayListParts; //在部分中第一个点的索引

publicArrayListPoints; //所有部分的点

}

PolyLine_shapepolyline = newPolyLine_shape();//实例化一个多段线

 



头信息
intRecordNum = br.ReadInt32();

 

RecordNum = Convert.ToInt32(big2little(RecordNum));

intDataLength = br.ReadInt32();

DataLength = Convert.ToInt32(big2little(DataLength));

Int ShapeType =br.ReadInt32(); // 读取本条记录的shape类型

polyline.Box[0] = br.ReadDouble();//xmin

polyline.Box[1] = br.ReadDouble();//ymin

polyline.Box[2] = br.ReadDouble();//xmax

polyline.Box[3] = br.ReadDouble();//ymax

polyline.NumParts = br.ReadInt32();//组成多段线部分数量

polyline.NumPoints = br.ReadInt32();//组成该多段线总的特征点数

//接着的数据存储的是各个组成多段线各部分第一个点在总point集合中的位置。

//他是一个长度为NumParts 的数组,所以一下使用一个for循环来将这些点的索引位置信息读出来,并存储在结构体中

for(int i = 0; i < polyline.NumParts; i++)

{

int parts = newint();

parts = br.ReadInt32();

polyline.Parts.Add(parts);

}

 

//读完点的索引信息后,就是点的信息,由于点的信息也是就是长度为Numpoints

的数组。所以,使用for循环来分别读取,并实例化成点添加到多段线的实例中去。

structPoint_shape // 定义点的结构体

{

publicdoubleX;

publicdoubleY;

}


for(int j = 0; j < polyline.NumPoints; j++)

{

Point_shape pointtemp = newPoint_shape();//实例化点

pointtemp.X = br.ReadDouble();

pointtemp.Y = br.ReadDouble();

polyline.Points.Add(pointtemp); //将点的信息添加到多段线的实例中

}

//以上的头信息和数据信息组成了一条完整的记录。

//接下来的数据都是重复上述的信息结构。

//因此整体要读取所有的记录信息的话就需要按照以下的方法来依次读取。

//还是以读取ployline为例来读取

//1、 读取shape文件的头信息。
//
BinaryReader br = new BinaryReader(openFileDialog1.OpenFile());
// br.read(99);读取前99个字节,就可以将头信息读取完。

ArrayList polylines = newArrayList();//创建一个容器,用于存储多条记录的数组

polylines.Clear();

//2、逐条读取记录的条文信息

While(br.PeekChar() != -1){ // br是指的数据流

PolyLine_shape polyline = newPolyLine_shape();//实例化一个多段线

//读取头信息

//读取数据信息

polylines.Add(polyline);

}

// 最终获得polylines中包含了所有的多段线的信息。

//采用如下方法可以将获得的信息写入到文本中。

Public WritePloyLineInfoToTxt(){

StreamWritersw2 = newStreamWriter("line.txt");

count = 1;

foreach (PolyLine_shapep in polylines)

{

for (inti = 0; i < p.NumParts; i++){

intstartpoint;

int endpoint;

if(i == p.NumParts - 1)

{

startpoint = (int)p.Parts[i];

endpoint = p.NumPoints;

}

else

{

startpoint = (int)p.Parts[i];

endpoint = (int)p.Parts[i + 1];

}

sw2.WriteLine("线" + count.ToString() + ":");

for(j = startpoint; j < endpoint; j++)

{

Point_shapeps = (Point_shape)p.Points[j];

sw2.WriteLine("{0},{1},{2} ", ps.X, ps.Y, 0);

}

count++;

}

}

sw2.Close();

}
以上代码可以直接复制到程序中直接使用,解析shape 格式数据,需要更多的



https://wap.sciencenet.cn/blog-686087-713229.html

上一篇:如何实现窗体上的组件自由拖动和变换大小
下一篇:c# 实现点到直线的距离
收藏 IP: 101.5.120.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-5-14 13:47

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部