Shapefile 是一种用于存储地理要素的几何位置和属性信息的非拓扑简单格式。shapefile 中的地理要素可通过点、线或面(区域)来表示。包含 shapefile 的工作空间还可以包含 dBASE 表,它们用于存储可连接到 shapefile 的要素的附加属性。
下面是 shapefile 如何在 ArcCatalog 中显示的示例。还能看到 dBASE 文件(它可能与 shapefile 相关联)。
默认情况下,具有文件扩展名 .txt、.asc、.csv 或 .tab 的所有文件将以文本文件的形式显示在 ArcCatalog 中。但在选项 对话框中,您可以选择其中哪些文件类型应显示为文本文件以及哪些不能显示在目录树中。当文本文件包含逗号分隔和制表符分隔的值时,您能够在 ArcCatalog 表视图中看到它们的内容并可将其连接到地理要素。在 ArcCatalog 中,可将文本文件删除,但其内容为只读。
可以在图层“属性”对话框的连接和关联选项卡中,将 dBASE 表或文本文件中存储的属性连接到 shapefile 中的要素。如果表包含描述空间位置的信息(例如,x,y,z 坐标或街道地址),则可以使用 ArcCatalog 中提供的工具创建用以表示这些位置的 shapefile。
旧版本:
除 shapefile 和表之外,ArcView GIS 用户还可以处理项目文件、图例文件和 Avenue 脚本。虽然无法直接在 ArcGIS Desktop 中处理这些项目,但可以通过 ArcCatalog 对其进行管理。要在 ArcCatalog 中查看这些项目,必须将其文件扩展名添加到文件类型列表中。例如,要查看 ArcView GIS 项目,请将文件扩展名 .apr 添加到列表中。
Shapefile 是一种用于存储地理要素的几何位置和属性信息的非拓扑简单格式。Shapefile 是可以在 ArcGIS 中使用和编辑的其中一种空间数据格式。
shapefile 格式在应存储在同一项目工作空间且使用特定文件扩展名的三个或更多文件中定义地理配准要素的几何和属性。这些文件是:
几何与属性是一对一关系,这种关系基于记录编号。dBASE 文件中的属性记录必须与主文件中的记录采用相同的顺序。
各文件必须具有相同的前缀,例如,roads.shp、roads.shx 和 roads.dbf。
在 ArcCatalog(或任何 ArcGIS 应用程序)中查看 Shapefile 时,将仅能看到一个代表 Shapefile 的文件;但可以使用 Windows 资源管理器查看与 Shapefile 相关联的所有文件。复制 Shapefile 时,建议在 ArcCatalog 中或者使用地理处理工具执行该操作。但如果在 ArcGIS 之外复制 shapefile,确保复制组成该 shapefile 的所有文件。
可以在具有任意许可等级的 ArcGIS Desktop(ArcGIS Desktop Basic、ArcGIS Desktop Standard或 ArcGIS Desktop Advanced)中编辑 shapefile。但要想利用高级编辑功能(例如,拓扑),则需要将 shapefile 作为要素类导入到地理数据库中。
了解有关在 ArcGIS 中进行编辑的详细信息
shapefile 中的所有要素类型都会在地理数据库中转换为几何类型。与 coverage 不同的是,shapefile 要素类型与地理数据库中存储的几何类型相类似,因此转换要更为简单。有关详细信息,请参阅导入时数据如何进行转换。
组成 shapefile 的每个文件均被限制为 2 GB。因此,.dbf 文件不能超过 2 GB,.shp 文件也不能超过 2 GB(只有这两个文件的容量会很大)。所有组成文件的总大小可以超过 2 GB。
多年以来,Esri 研发了三种用于存储地理信息的主要数据格式:coverage、shapefile 以及地理数据库。其中,Shapefile 为存储地理及属性信息提供了一种简单的格式。正由于 shapefile 的简易性,使其成为一种非常流行的开放式数据转换格式。凭借其简易性,shapefile 似乎已成为人们的必然选择,然而,在它的使用中,仍然存在由地理数据库地址所决定的局限性。因此,使用 shapefile 时,应注意其局限性。概括如下:
正因为存在这些(或更多)问题,如果选用 shapefile 进行活动数据库管理将显得捉襟见肘 - 它们无法处理现今数据的创建、编辑、版本管理及归档的生命周期。
除以下列出的一些特例外,可以使用 shapefile 来存储简单的要素几何。不过,shapefile 在属性存储上存在严重问题。例如,它们无法存储空值,无法向上舍入数字,对 Unicode 字符串的支持不足,字段名称最长只能为 10 个字符,且无法在日期字段中存储时间。这些只是其中的主要问题。此外,它们不支持在地理数据库中的某些功能,如:属性域和子类型。因此,除非是非常简单的属性且不需要使用地理数据库功能,否则请不要使用 shapefile。
Shapefile 存储在三个或更多个具有相同前缀的文件中,且位于同一系统文件夹(shapefile 工作空间)中。使用 Windows 资源管理器而非 ArcCatalog 查看该文件夹时,可以看到单个文件。
扩展名 |
说明 |
必需的文件? |
---|---|---|
.shp |
用于存储要素几何的主文件。此文件中未存储任何属性 - 仅有几何。 |
是 |
.shx |
.shp 的配套文件,用于存储 .shp 文件中各个要素 ID 的位置。 |
是 |
.dbf |
用于存储要素属性信息的 dBASE 表。 |
是 |
.sbn 和 .sbx |
用于存储要素空间索引的文件。 |
否 |
.atx |
为各 dBASE 属性索引(建立于 ArcCatalog 中)而创建。 |
否 |
.ixs 和 .mxs |
读写 shapefile 的地理编码索引。 |
否 |
.prj |
用于存储坐标系信息的文件。 |
否 |
.xml |
ArcGIS 的元数据;用于存储 shapefile 的相关信息。 |
否 |
地理数据库数据类型 |
dBASE 字段类型 |
dBASE 字段宽度(字符数) |
---|---|---|
对象 ID |
数值 |
9 |
短整型 |
数值 |
4 |
长整型 |
数值 |
9 |
浮点型 |
浮点型 |
13 |
双精度型 |
浮点型 |
13 |
文本 |
字符 |
254 |
日期 |
日期 |
8 |
注:
若您的字段名称或字段值需要支持 Unicode,则强烈建议您使用地理数据库,而非 shapefile。
警告:
对于执行时态分析的所有工具(例如时空模式挖掘工具箱中的工具)而言,日期字段不支持时间是一个严重限制。请避免使用 shapefile 进行任何类型的时态分析或日期时间计算。
Shapefile 不支持空值。如果将含有空值的要素类转换为 shapefile 或将数据库表转换为 dBASE 文件,则将按下表所述更改空值。
警告:
当将 shapefile 或 dBASE (.dbf) 文件用作工具的输入时,ArcGIS 无法确定某一字段值表示空值还是合法值。
包含空值的数据类型 |
空值替换 |
---|---|
数字 - 当工具需要输出“空”、无穷大或 NaN(非数字)时 |
-1.7976931348623158e+308(最大负值的 IEEE 标准) |
数字(所有其他地理处理工具) |
0 |
文本 |
“ ”(空白 - 单空格) |
日期 |
存储为零,但显示为 <空> |
Shapefile 在工作空间或要素类级别无扩展数据类型。因此,从地理数据库要素类或其他格式转换为 shapefile 时会导致下列数据丢失:
对于存储在地理数据库中的线或面要素类,ArcGIS 会计算并维护 shape_length 和 shape_area 字段;也就是说,编辑地理数据库要素类中的线形状或面形状时,系统会重新计算 shape_length 和 shape_area 字段中的值以反映对要素所做的编辑。但这不适用于 shapefile。即使 shapefile 具有 shape_area 或 shape_leng 字段,对 shapefile 进行编辑后,字段也不会更新。
任何能够输出要素类的地理处理工具,均可选择 shapefile 或地理数据库要素类作为输出格式。同样,任意输出结果为表的工具,均可选择 dBASE 文件 (.dbf) 或地理数据库表作为输出格式。需要始终了解所使用的格式,以及将地理数据库输入转换为 shapefile 输出所产生的后果。
地理处理工具可自动生成输出要素类或表。自动生成的输出基于使用当前及临时工作空间环境中所述的许多因素。若您的临时工作空间环境未设置为某个地理数据库,而是设置为了某个系统文件夹,则自动生成的输出要素类将为 shapefile 或 dBASE 文件,如下图所示。
建议您将临时工作空间设置为某个文件地理数据库,以便自动生成的输出不会被写入 shapefile 或 .dbf 表中,而是被写入文件地理数据库中。
了解有关地理处理环境的详细信息
由于 shapefile 写入速度快,通常将它作为模型的中间数据使用,从而可加快模型执行速度。不过,写入文件地理数据库与写入 shapefile 的速度几乎相同,所以除非对执行速度的要求较高,否则应始终使用文件地理数据库写入中间数据及输出数据。若您一定要使用 shapefile,请注意上述局限性,且仅将 shapefile 用于简单要素和属性。将 shapefile 用于中间数据的替代方法是将要素写入 in_memory 工作空间。
通常,shapefile 并不包含任何用于确定已使用哪个坐标系来定义其要素的信息。在这种情况下,“形状”列的“空间参考”属性将为“未知”或“假定地理”。如果要素的边界坐标在 x 方向上介于 -180 到 180 范围内,在 y 方向上介于 -90 到 90 范围内,ArcGIS 会认为该数据为地理数据,其基准面为 NAD27。如果边界坐标不在该范围内,软件会认为空间参考为未知。
了解有关坐标系的详细信息
即使 shapefile 的坐标系未定义,也可以使用相应的 shapefile,但可能无法利用所有可用功能。例如,shapefile 可能不能与其他数据排列在一起,这样,其自动创建的元数据将是不完整的。
在 ArcCatalog 中可以多种方式定义 shapefile 的坐标系:
坐标系参数必须保存在 shapefile 所在文件夹的 .prj 文件中,并且 .prj 文件必须与 shapefile 具有相同的文件前缀。例如,如果您正在使用名为 wells.shp 的 shapefile,那么其坐标系参数必须存储在同一文件夹的 wells.prj 文件中。
定义坐标系后,可以修改各参数。例如,您可能想要修改坐标系中从另一数据源导入的一个参数或者对其中一个预定义坐标系进行自定义。创建自定义坐标系后,可以将其另存为单独的坐标系文件;您可能需要与您所在组织中的其他人共享该坐标系。
要在 ArcCatalog 中添加或修改 shapefile 的坐标系,请使用“投影”工具或“创建空间参考”工具。
本文只做记录,参考资料均来源于网络,版权归原作者所有。
ESRI 的 shape 文件由一个主文件(.shp)、一个索引文件(.shx)和一个 dBASE 表(.dbf)构成。主文件(.shp)是一个可变记录长度的随机文件,文件中的每个记录描述一个包含多个顶点的 shape。在索引文件(.shx)中,每个记录内容包含着与主文件中记录相对应的从主文件开始处的偏移量。dBASE 表(.dbf)中包含着与每个要素相对应的一条要素属性记录。几何数据与属性的一一对应关系是基于记录号来对应的。dBASE 文件中属性记录的顺序必须与主文件中的记录顺序相同。
主文件(.shp)用于记录空间坐标信息,包含一个固定长度的文件头,在文件头的后面存储着可变长度的记录。每个可变长度记录由一个固定长度的记录头和跟随其后的可变长度记录内容组成。
主文件头长度为 100 字节,一共有9个int型和8个double型数据。
注:表中最后4个加星号特别标示的四个数据只有当这个Shapefile文件包含Z方向坐标或者具有Measure值时才有值,否则为0.0。所谓Measure值,是用于存储需要的附加数据,可以用来记录各种数据,例如权值、道路长度等信息。
Shapefile文件所支持的几何类型:
注:对于一个不是记录Null Shape 类型的Shapefile文件,它所记录的空间目标的几何类型必须一致,不能在一个Shapefile文件中同时记录两种不同类型的几何目标。
读取坐标文件(.shp)的文件头的代码如下:
void OnReadShp(CString ShpFileName)
{
FILE* m_ShpFile_fp; //****Shp文件指针
//打开坐标文件
if((m_ShpFile_fp=fopen(ShpFileName,"rb"))==NULL)
{
return;
}
//读取坐标文件头的内容 开始
int FileCode;
int Unused;
int FileLength;
int Version;
int ShapeType;
double Xmin;
double Ymin;
double Xmax;
double Ymax;
double Zmin;
double Zmax;
double Mmin;
double Mmax;
fread(&FileCode, sizeof(int), 1,m_ShpFile_fp);
FileCode = OnChangeByteOrder (FileCode);
for(i=0;i<5;i++)
fread(&Unused,sizeof(int), 1,m_ShpFile_fp);
fread(&FileLength, sizeof(int), 1,m_ShpFile_fp);
FileLength = OnChangeByteOrder (FileLength);
fread(&Version, sizeof(int), 1,m_ShpFile_fp);
fread(&ShapeType, sizeof(int), 1,m_ShpFile_fp);
fread(&Xmin, sizeof(double),1,m_ShpFile_fp);
fread(&Ymin, sizeof(double),1,m_ShpFile_fp);
fread(&Xmax, sizeof(double),1,m_ShpFile_fp);
fread(&Ymax, sizeof(double),1,m_ShpFile_fp);
fread(&Zmin, sizeof(double),1,m_ShpFile_fp);
fread(&Zmax, sizeof(double),1,m_ShpFile_fp);
fread(&Mmin, sizeof(double),1,m_ShpFile_fp);
fread(&Mmax, sizeof(double),1,m_ShpFile_fp);
//读取坐标文件头的内容 结束
//根据几何类型读取实体信息
……
}
每个记录段分为记录头和记录内容两部分。
每个记录的记录头都储存着记录号和记录内容的长度,记录头的长度是 8 个字节,记
录号从 1 开始。字节位置是相对于记录头算起的。记录头的内容包括记录号(Record Number)和坐标记录长度(Content Length) 两个记录项。它们的位序都是big。记录号(Record Number)和坐标记录长度(Content Length) 两个记录项都是int型,并且shapefile文件中的记录号都是从1开始的。
Shape 文件的记录内容由 shape 类型和其后面的 shape 的几何数据组成。记录内容的长度取决于 part 的数量和 shape 的顶点数目。对于每个 shape 类型,我们先给出它的描述,然后是它在磁盘上的记录内容。position 是从记录内容的开始算起的。记录内容包括目标的几何类型(ShapeType)和具体的坐标记录(X、Y) ,记录内容因要素几何类型的不同其具体的内容及格式都有所不同。
具体分为以下几种:
Shape 类型为 0 表示一个没有几何类据的空的(Null)shape。每个要素类型(point、line、polygon 等等)都支持“空状态”-在同一个 shape 文件中“有点”(have point)和“无点”(null point)都是合法的。空 shape 经常作为位置标志符来使用,在创建 shape 文件时使用它,稍后就会被填充为几何数据。
一个 Point 由一对双精度坐标组成,存储顺序为 X,Y。
Point
{
Double X // X coordinate
Double Y // Y coordinate
}
下面是读取点状目标的记录内容的代码:
OnReadPointShp(CString ShpFileName)
{
//打开坐标文件
……
//读取坐标文件头的内容 开始
……
//读取点状目标的实体信息
int RecordNumber;
int ContentLength;
int num =0;
while((fread(&RecordNumber, sizeof(int), 1,ShpFile_fp)!=0))
{
num++;
fread(&ContentLength,sizeof(int), 1,ShpFile_fp);
RecordNumber = OnChangeByteOrder (RecordNumber);
ContentLength = OnChangeByteOrder (ContentLength);
int shapeType;
double x;
double y;
fread(&shapeType, sizeof(int), 1,ShpFile_fp);
fread(&x, sizeof(double), 1,ShpFile_fp);
fread(&y, sizeof(double), 1,ShpFile_fp);
}
}
一个 MultiPoint 描述一组点, 具体如下:
MultiPoint
{
Double[4] Box // Bounding Box
Integer NumPoints // Number of Points
Point[NumPoints] Points // The Points in the set
}
Bounding box 的存储顺是 Xmin, Ymin, Xmax, Ymax.
一条弧段是一个按次序排列的顶点序列,包含一个或几个 part,一个 part 是由两个或两个以上的点连接而成的序列,Part 之间互相连接或不连接均可,Part 之间可以交叉也可以不交叉。Shapefile允许出现多个坐标完全相同的连续点,当读取文件时一定要注意这种情况,但是不允许出现某个退化的、长度为0的子线段出现。
Arc
{
Double[4] Box // Bounding Box
Integer NumParts // Number of Parts
Integer NumPoints // Total Number of Points
Integer[NumParts] Parts // Index to first Point in Part
Point[NumPoints] Points // Points for all parts
}
各个字段描述如下:
Box: Arc 的 Bounding box,按照 Xmin, Ymin, Xmax, Ymax 的顺序存储。
NumParts: Arc 中 Part 的数目。
NumPoints: 所有 Part 的总点数。
Parts: 长度为 NumParts 的数组,存储着每个 part(注:原文中是 polyline)的起始点在 points 数组中的索引,索引从 0 开始。
Points: 长度为 NumPoints 的数组,按顺序存储构成 Arc 的所有 Part 的点。组成序号为 2 的 Part 的点紧接着序号为 1 的,依此类推。数组 Parts 中存储着每个 Part 起点的数组索引。在 points 数组中,各 Part 之间没有分隔符。
下面是读取线状目标的记录内容的代码:
OnReadLineShp(CString ShpFileName)
{
//打开坐标文件
……
//读取坐标文件头的内容 开始
……
//读取线状目标的实体信息
int RecordNumber;
int ContentLength;
int num =0;
while((fread(&RecordNumber, sizeof(int), 1,ShpFile_fp)!=0))
{
fread(&ContentLength,sizeof(int), 1,ShpFile_fp);
RecordNumber = OnChangeByteOrder (RecordNumber);
ContentLength = OnChangeByteOrder (ContentLength);
int shapeType;
double Box[4];
int NumParts;
int NumPoints;
int *Parts;
fread(&shapeType, sizeof(int), 1,ShpFile_fp);
//读Box
for(i=0;i<4;i++)
fread(Box+i, sizeof(double),1,ShpFile_fp);
//读NumParts和NumPoints
fread(&NumParts, sizeof(int), 1,ShpFile_fp);
fread(&NumPoints, sizeof(int), 1,ShpFile_fp);
//读Parts和Points
Parts =new int[NumParts];
for(i=0;i
Polygon 由一个或多个环组成。环是一个由 4 个或 4 个以上的顺序连接的点构成的闭
合的、非自相交的回路。Polygon 可以包含多个外部环。顶点的顺序或方向表明环的哪一
侧是处于 Polygon 内部的。沿着一个环的顶点顺序前进,前进方向的右侧就是这个环所在
的 Polygon。在 Polygon 中由顶点组成的洞是逆时针方向的。单一且闭合的 Polygon 的结
点顺序总是顺时针方向的。组成 Polygon 的 ring 就是 Polygon 的 Part。
Polygon
{
Double[4] Box // Bounding Box
Integer NumParts // Number of Parts
Integer NumPoints // Total Number of Points
Integer[NumParts] Parts // Index to First Point in Part
Point[NumPoints] Points // Points for All Parts
}
Polygon 中各个字段的描述如下:
Box: Polygon 的封装边界,存储顺序为:Xmin, Ymin, Xmax, Ymax。
NumParts: Polygon 中环的个数。
NumPoints: 构成所有环的点的数目。
Parts: 长度为 NumParts 的数组,存储着每个环的首点在 Points 数组中的索引,数
组索引从 0 开始。
Points: 长度为 NumPoints 的数组。构成 Polygon 的每个环的点,按照首尾相连的顺序存储的。组成序号为 2 的环的点紧接着序号为 1 的环,依此类推。数组Parts 中存储着每个环的起点的数组索引。组成不同环的点之间没有分隔符。
对于一个shapefile中的多边形,它必须满足下面三个条件:
(1)构成多边形的每个子环都必须是闭合的,即每个子环的第一个顶点跟最后一个顶点是同一个点;
(2)每个子环在Points数组中的排列顺序并不重要,但每个子环的顶点必须按照一定的顺序连续排列;
(3)存储在shapefile 中的多边形必须是干净的。所谓一个干净的多边形,它必须满足两点:
1)没有自相交现象。这就要求任何一个子环不能跟其它的子环相交,共线的现 象也将被当作相交。但是允许两个子环的顶点重合;
2) 对于一个不含岛的多边形或者是含岛的多边形的外环,它们的顶点排列顺序必须是顺时针方向;而对于内环,它的排列顺序必须是逆时针方向。所谓的“脏多边形”就是指顶点排列顺序为顺时针的内环。
典型多边形示例:
下图中这个多边形包括一个岛,所有顶点的个数为8。NumParts等于2,NumPoints等于10。请注意内环(岛)的顶点的排列顺序是逆时针的。
下面是读取Polygon(面)的记录内容的代码:
void OnReadAreaShp(CString ShpFileName)
{
//打开坐标文件
……
//读取坐标文件头的内容 开始
……
//读取面状目标的实体信息
int RecordNumber;
int ContentLength;
while((fread(&RecordNumber, sizeof(int), 1,m_ShpFile_fp)!=0))
{
fread(&ContentLength,sizeof(int), 1,m_ShpFile_fp);
RecordNumber = OnChangeByteOrder (RecordNumber);
ContentLength = OnChangeByteOrder (ContentLength);
int shapeType;
double Box[4];
int NumParts;
int NumPoints;
int *Parts;
fread(&shapeType, sizeof(int), 1,m_ShpFile_fp);
//读Box
for(i=0;i<4;i++)
fread(Box+i, sizeof(double),1,m_ShpFile_fp);
//读NumParts和NumPoints
fread(&NumParts, sizeof(int), 1,m_ShpFile_fp);
fread(&NumPoints, sizeof(int), 1,m_ShpFile_fp);
//读Parts和Points
Parts =new int[NumParts];
for(i=0;i
索引文件(.shx)由一个长度为 100 字节的文件头引导,后面是一系列长度为 8 字节的记录。
索引文件文件头的组织形式与上面的主文件文件头的描述是一样的。文件头中存储的文件长度是以 16 字节表示的文件的总长度(文件头的 50 个 16 字节 加上记录个数的 4 倍)。
索引文件中的第 I 个记录存储着第 I 个记录在主文件中的偏移量和内容长度。表中显示了文件头中的各个字段以及它们的位置、值、类型、字节顺序。表中的位置是从索引文件记录的开始算起的。
一个记录在主文件中的偏移量是用 16 字节表示的,它表示从主文件开始至这个记录记录头第一个字节的 word 个数。因此,主文件中的第一个记录的偏移量是 50。索引记录中存储的内容长度与主文件中记录头中存储的数值相同。
下面是一段读取索引文件的代码:
void OnReadShx(CString ShxFileName)
{
FILE* m_ShxFile_fp; //****Shx文件指针
//打开索引文件
if((m_ShxFile_fp=fopen(ShxFileName,"rb"))==NULL)
{
return;
}
//读取索引文件头的内容 开始
int FileCode;
int Unused;
int FileLength;
int Version;
int ShapeType;
double Xmin;
double Ymin;
double Xmax;
double Ymax;
double Zmin;
double Zmax;
double Mmin;
double Mmax;
fread(&FileCode, sizeof(int), 1,m_ShxFile_fp);
FileCode = OnChangeByteOrder (FileCode);
for(i=0;i<5;i++)
fread(&Unused,sizeof(int), 1,m_ShxFile_fp);
fread(&FileLength, sizeof(int), 1,m_ShxFile_fp);
FileLength = OnChangeByteOrder (FileLength);
fread(&Version, sizeof(int), 1,m_ShxFile_fp);
fread(&ShapeType, sizeof(int), 1,m_ShxFile_fp);
fread(&Xmin, sizeof(double),1,m_ShxFile_fp);
fread(&Ymin, sizeof(double),1,m_ShxFile_fp);
fread(&Xmax, sizeof(double),1,m_ShxFile_fp);
fread(&Ymax, sizeof(double),1,m_ShxFile_fp);
fread(&Zmin, sizeof(double),1,m_ShxFile_fp);
fread(&Zmax, sizeof(double),1,m_ShxFile_fp);
fread(&Mmin, sizeof(double),1,m_ShxFile_fp);
fread(&Mmax, sizeof(double),1,m_ShxFile_fp);
//读取索引文件头的内容 结束
int Offset, ContentLength;
//读取实体信息
while((fread(&Offset, sizeof(int), 1, m_ShxFile_fp)!=0))
{
fread(&ContentLength,sizeof(int), 1, m_ShxFile_fp);
Offset = OnChangeByteOrder (Offset);
ContentLength = OnChangeByteOrder (ContentLength);
}
}
dBASE 文件(.dbf)中包含任何需要的要素属性或可供其它表连接的属性关键字。它是标准的 DBF 格式文件,广泛应用于诸多的 Windows 和 DOS 平台上基于表格的应用程序。各类字段都可被引入到表中。
其中文件头部分的长度是不定长的,它主要对DBF文件作了一些总体说明,其中最主要的是对这个DBF文件的记录项的信息进行了详细地描述,比如对每个记录项的名称、数据类型、长度等信息都有具体的说明。
实体信息部分就是一条条属性记录,每条记录都是由若干个记录项构成,因此只要依次循环读取每条记录就可以了。
假设要读取一个名为soil的dbf文件(存储了土地利用信息),它含有8个记录项。
下面是读取这个dbf文件的代码:
void OnReadDbf(CString DbfFileName)
{
FILE* m_DbfFile_fp; //****Dbf文件指针
//打开dbf文件
if((m_DbfFile_fp=fopen(DbfFileName,"rb"))==NULL)
{
return;
}
int i,j;
//****读取dbf文件的文件头 开始
BYTE version;
fread(&version, 1, 1,m_DbfFile_fp);
BYTE date[3];
for(i=0;i<3;i++)
{
fread(date+i, 1, 1,m_DbfFile_fp);
}
int RecordNum; //******
fread(&RecordNum, sizeof(int), 1,m_DbfFile_fp);
short HeaderByteNum;
fread(&HeaderByteNum, sizeof(short), 1,m_DbfFile_fp);
short RecordByteNum
fread(&RecordByteNum, sizeof(short), 1,m_DbfFile_fp);
short Reserved1;
fread(&Reserved1, sizeof(short), 1,m_DbfFile_fp);
BYTE Flag4s;
fread(&Flag4s, sizeof(BYTE), 1,m_DbfFile_fp);
BYTE EncrypteFlag;
fread(&EncrypteFlag, sizeof(BYTE), 1,m_DbfFile_fp);
for(i=0;i<3;i++)
{
fread(&Unused, sizeof(int), 1,m_DbfFile_fp);
}
BYTE MDXFlag;
fread(&MDXFlag, sizeof(BYTE), 1,m_DbfFile_fp);
BYTE LDriID;
fread(&LDriID, sizeof(BYTE), 1,m_DbfFile_fp);
short Reserved2;
fread(&Reserved2, sizeof(short), 1,m_DbfFile_fp);
BYTE name[11];
BYTE fieldType;
int Reserved3;
BYTE fieldLength;
BYTE decimalCount;
short Reserved4;
BYTE workID;
short Reserved5[5];
BYTE mDXFlag1;
int fieldscount;
fieldscount = (HeaderByteNum - 32) / 32;
//读取记录项信息-共有8个记录项
for(i=0;i< HeaderByteNum;i++)
{
//FieldName----11 bytes
fread(name, 11, 1,m_DbfFile_fp);
//FieldType----1 bytes
fread(&fieldType, sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved3----4 bytes
Reserved3 =0;
fread(&Reserved3, sizeof(int), 1,m_DbfFile_fp);
//FieldLength--1 bytes
fread(&fieldLength,sizeof(BYTE), 1,m_DbfFile_fp);
//DecimalCount-1 bytes
fread(&decimalCount,sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved4----2 bytes
Reserved4 =0;
fread(&Reserved4, sizeof(short), 1,m_DbfFile_fp);
//WorkID-------1 bytes
fread(&workID, sizeof(BYTE), 1,m_DbfFile_fp);
//Reserved5----10 bytes
for(j=0;j<5;j++)
{
fread(Reserved5+j,sizeof(short), 1,m_DbfFile_fp);
}
//MDXFlag1-----1 bytes
fread(&mDXFlag1, sizeof(BYTE), 1,m_DbfFile_fp);
}
BYTE terminator;
fread(&terminator, sizeof(BYTE), 1,m_DbfFile_fp);
//读取dbf文件头结束
double Area,Perimeter,Centroid_y,Centroid_x;
int Soils_,Soils_id;
CString Soil_code,suit;
BYTE deleteFlag;
char media[31];
//读取dbf文件记录 开始
for(i=0;i
ArcGIS使用shapefile文件保存几何图形的位置及相关属性,Shapefile文件是一种按特定规列存储的二进制文件,实际上该种文件格式包含多个文件。Shapefile中".shp"、 ".shx"、 ".dbf"和”.prj”文件必不可少,例如,一个以“ZD”(宗地)为命名的Shapefile中就必须有ZD.shp、ZD.shx、ZD.dbf、ZD.prj四个文件。
Shapefile图形格式 (.shp)
Shapefile格式的主文件包含了地理参照数据。该文件由一个定长的文件头和一个或若干个变长的记录数据组成。每一条变长数据记录包含一个记录头和一些记录内容。
1.1文件头
主文件头包含17个字段,共100个字节,其中包含九个4字节(32位有符号整数,Integer)整数字段,紧接着是八个8字节(双精度浮点数)有符号浮点数字段。
其中:
文件的字节数需在所有图形输出完成后补写,头文件中的所有内容均可在最后补写。
Shapefile中所有图形的外接矩形,可以在所有图形输出完成后补写。
文件的更新信息:ArcGIS10.1以前的版本就9994,以后的版本是19988。
1.2图形数据
图形数据包含记录头和记录内容二部分,长度根据记录类型和形状确定。
1.2.1点要素的输出内容
设:已有图形数据的总长度=i
1.2.2线要素的输出内容
设:已有图形数据的总长度=i;线数=xi,点数=N
其中大多数情况:线数=1、点序=0
记录长度=4(记录类型)+32(图形边界合)+4(线数)+4(总点数)+xi*4(点序)+N*16(坐标X、Y)
1.2.3面要素的输出内容
设:已有图形数据的总长度=i;环数=qi,点数=N
其中:
1.封闭多段线表示的面 环数=1、环序=0;
2.填充图案表示的面(弧岛)外环的坐标应是顺时针,还必须回到第一点;
3.内环的坐标应是逆时针,也必须回到第一点。
记录长度=4(记录类型)+32(图形边界合)+4(环数)+4(总点数)+qi*4(点序)+N*16(坐标X、Y)
每一个要素输出后,文件的字节数=LOF(ShpFile);
第一个要素的开始位置=101(100为头文件);
以后每一个要素的开始位置= LOF(ShpFile)+1。
1.3字节序
小端序是正常的数。
大端序是把数字由十进制转十六进制,把十六进制数每二位为一节进行倒序后再用十进制来表示。如:
19988 转为十六进制 270A 倒序 0A270000 用十进制来表示 170328064
1000 转为十六进制 1F4 倒序 F4010000 用十进制来表示 -201261056
Shapefile索引文件(.shx)
索引文件(.Shx)前100个字节是文件头,内容和数据文件(.shp)一样,可以在输出数据文件时同时输出。
索引文件的图形信息只有二项:开始位置、记录长度
3. Shapefile属性文件(. dbf)
对于CAD输出Shape文件来说,数据文件(.shp)的结构虽然复杂,但输出方法是不变的,一次把代码写好,可以适用于任何项目的转换。属性是变化的,每一个项目都不同,以往的解决方法是给CAD图形赋上与转出结构一样的扩展属性,这样CAD图形的数据量增加,不便于查看和编辑,本文介绍一种动状处理属性文件中属性项的办法。
对需要转换Shape文件的项目编制一个配置文件,文件是一个Excel文件,每一张表代表一个转出图层,其中规定了CAD图形的选择集过滤器、Shape文件类型、字段数、字段总长度以及创建字段的清单。如下图:
第一行是转出Shape文件的文件名=ZD;
第二行CAD选择集过滤器为:8 地块 (表示 图层=地块);
第三行CAD选择集过滤器为:0 *Polyline,Region,Hatch (类型=多段线,面域,填充图案)
第四行是文件的要素类型;
第五行是字段数量(不包括Shp自动生成的Shape字段和ID字段 ;
第六行是字段的总长度;
第八行开始是字段清单。
其中:
第一列是字段名,字段名不支持中文,并且最多只能有11个字符。
第二列是字段类型,这理是字段类型代码的ASCLL值,Shape中规定字段类型应输入这个值。几种常用类型的取值见下表:
***ArcGIS10.2不支持逻辑型字段
第三列是字段长度;
第四列是字段精度(小数的位数,只有双精度类型的字段需要)
第六列是取值方法,有:编号、扩展属性、黙认值、X坐标、Y坐标、Z坐标六个选项。
编号:按输出顺序自动编号获取
扩展属性:提取输出图形扩展属性第i项的值,i= 第七列中的数字
黙认值:第七列中的数据
X坐标:点要素的插入点坐标、面要素的中心点坐标的X值
Y坐标:点要素的插入点坐标、面要素的中心点坐标的Y值
Z坐标:点要素的插入点坐标、面要素的中心点坐标的Y值
4. Shapefile空间参考(.prj)
空间参考文件是shp 的地图投影信息,可以复制同类项目的投影文件,也可以根据4个参数(坐标系统、中央子午线、投影带宽、横坐标是否加带号)来编辑组成,内容如下:
PROJCS["Xian_1980_3_Degree_GK_CM_117E",
GEOGCS["GCS_Xian_1980",
DATUM["D_Xian_1980",
SPHEROID["Xian_1980",6378140.0,298.257]],
PRIMEM["Greenwich",0.0],
UNIT["Degree",0.0174532925199433]],
PROJECTION["Gauss_Kruger"],
PARAMETER["False_Easting",500000.0],
PARAMETER["False_Northing",0.0],
PARAMETER["Central_Meridian",117],
PARAMETER["Scale_Factor",1.0],
PARAMETER["Latitude_Of_Origin",0.0],
UNIT["Meter",1.0]]
Public 坐标系 As String, 加带号 As Boolean, 中央子午线 As Double, 投影带宽 As Integer
Public Type 字段属性
Name As String '字段名
Type As Byte '字段类型
Length As Byte '字段长度
pScale As Byte '字段精度
Method As String '取值方法
Number As Integer '属性项序号
Value As Variant '黙认值
End Type
Dim pField() As 字段属性 '字段组
Dim 字段数 As Integer
Dim 字段总长度 As Integer
Dim 文件头长度 As Integer
Dim 记录条数 As Long
Dim 记录长度 As Long
Dim 范围框(0 To 3) As Double
Dim 图形框(0 To 3) As Double
Dim ShpName As String, ShpFile As Integer, Shp指针 As Long 'Shp文件名、文件号、指针
Dim ShxName As String, ShxFile As Integer, Shx指针 As Long 'Shx文件名、文件号、指针
Dim DbfName As String, DbfFile As Integer, Dbf指针 As Long 'Dbf文件名、文件号、指针
Sub 创建空间参考文件()
创建空间参考.show
End Sub
Sub 动态属性转Shape()
Dim mm As String
Dim N As Long, i As Integer, r As Integer
Dim fType(1) As Integer, fData(1) '选择集过滤条件
Dim SelectA As AcadSelectionSet '选择集
Dim Entry As AcadEntity 'CAD实体
Dim XDType As Variant, xData As Variant '查询扩展属性
Dim longN As Long
Dim version As Byte
Dim dateF(2) As Byte
Dim 表名 As String, 发包方编码 As String
On Error Resume Next
Dim 工作目录 As String
工作目录 = "E:\ArcGIS\NEWShape\" 'ThisDrawing.Path + "\NEWShape\"
If InStr(工作目录, "C:\Program Files (x86)\AutoCAD 2008") > 0 Then Exit Sub
Call 创建目录(工作目录)
'创建空间参考文件
'定义空间参考.show '自定义选择参数 坐标系、加带号、中央子午线、投影带宽
坐标系 = "1980西安坐标系"
中央子午线 = 118.5
加带号 = False
投影带宽 = 3
Dim PrjName As String
PrjName = 投影文件(坐标系, 加带号, 中央子午线, 投影带宽)
发包方编码 = Left(ThisDrawing.Name, 12)
Dim 转换标准 As String 'Shape转换标准样本.xlsx
转换标准 = VBApath & "Shape转换标准样本.xlsx"
Workbooks.Open FileName:=转换标准 '打开文件
Dim MySheet As Worksheet 'Excel工作表
For Each MySheet In ActiveWorkbook.Sheets '历遍Excel的工作表
If MySheet.Name = "JZX" Or MySheet.Name = "说明" Then Exit For '目前不转界址线
表名 = 工作目录 & 发包方编码 & MySheet.Name
文件名 = 表名 + ".prj"
FileCopy PrjName, 文件名 '复制预先创建好的空间参考文件
ShpName = 表名 & ".shp": ShpFile = 1
ShxName = 表名 & ".shx": ShxFile = 2
DbfName = 表名 & ".dbf": DbfFile = 3
'如果文件已存在,删除文件
If Dir(ShpName) <> "" Then Kill ShpName
If Dir(ShxName) <> "" Then Kill ShxName
If Dir(DbfName) <> "" Then Kill DbfName
'创建打开Shape文件,输出头文件内容
Open ShpName For Binary As #ShpFile '打开文件
Open ShxName For Binary As #ShxFile '打开文件
Open DbfName For Binary As #DbfFile '打开文件
字段数 = MySheet.Cells(5, 2)
字段总长度 = MySheet.Cells(6, 2)
ReDim pField(字段数 - 1)
For i = 0 To 字段数 - 1
pField(i).Name = MySheet.Cells(i + 8, 1)
pField(i).Type = MySheet.Cells(i + 8, 2)
pField(i).Length = MySheet.Cells(i + 8, 3)
pField(i).pScale = MySheet.Cells(i + 8, 4)
pField(i).Method = MySheet.Cells(i + 8, 6)
Select Case pField(i).Method '取值方法
Case "扩展属性"
pField(i).Number = MySheet.Cells(i + 8, 7)
Case "黙认值"
pField(i).Value = MySheet.Cells(i + 8, 7)
End Select
r = 32 + i * 32
For N = 1 To 11 '只有11个字节 记录字段名,是ASCII码值,如果字段名超过11个字符会被舍去。
Put #DbfFile, r + N, Asc(Mid(pField(i).Name, N, 1))
Next
Put #DbfFile, r + 12, pField(i).Type
Put #DbfFile, r + 17, pField(i).Length
Put #DbfFile, r + 18, pField(i).pScale
Next
字段总长度 = 字段总长度 + 1
文件头长度 = 字段数 * 32 + 32 + 1
Put #DbfFile, 9, 文件头长度 '文件头长度
Put #DbfFile, 11, 字段总长度 '一条记录的字节长度
version = 3
Put #DbfFile, 1, version '版本信息
dateF(0) = 19: dateF(1) = 2: dateF(2) = 15
Put #DbfFile, 2, dateF '最近的更新日期
Put #DbfFile, 文件头长度, 13 '结束标志
longN = 170328064
Put #ShpFile, 1, longN '1 File Code
Put #ShxFile, 1, longN
longN = 1000
Put #ShpFile, 29, longN '1 版本号
Put #ShxFile, 29, longN
longN = MySheet.Cells(4, 2)
Put #ShpFile, 33, longN '33 几何类型
Put #ShxFile, 33, longN
'以下输出图形信息
范围框(0) = 100000000: 范围框(1) = 100000000
范围框(2) = 0: 范围框(3) = 0
Shp指针 = 101: 记录长度 = 101
Shx指针 = 101
记录条数 = 0
Dbf指针 = 文件头长度 + 1
r = LOF(DbfFile)
ThisDrawing.SelectionSets.Item("窗选").Delete
Err.Clear
Set SelectA = ThisDrawing.SelectionSets.Add("窗选")
fType(0) = MySheet.Cells(2, 1): fData(0) = MySheet.Cells(2, 3)
fType(1) = MySheet.Cells(3, 1): fData(1) = MySheet.Cells(3, 3)
SelectA.Select acSelectionSetAll, , , fType, fData
For Each Entry In SelectA
Entry.GetXData "", XDType, xData
记录条数 = 记录条数 + 2
For i = 0 To 字段数 - 1
Select Case pField(i).Method '取值方法
Case "扩展属性"
pField(i).Name = xData(pField(i).Number)
Case "黙认值"
pField(i).Name = pField(i).Value
Case "编号"
pField(i).Name = 记录条数 / 2
Case Else
pField(i).Name = ""
End Select
Next
Select Case MySheet.Cells(4, 2) 'Shape类型
Case 5 '面
Call Shape面记录内容(Entry)
Case 3 '线
Call Shape线记录内容(Entry)
Case 1 '点
Call Shape点记录内容(Entry)
End Select
Next
SelectA.Delete
'关闭Shape文件
Dim Offset As Long
N = 记录条数 / 2
Put #DbfFile, 5, N
Offset = LOF(ShpFile)
longN = 转为大端序(Offset)
Put #ShpFile, 25, longN 'Shp文件长度
longN = 转为大端序(Shx指针 - 1)
Put #ShxFile, 25, longN 'Shx文件长度
Put #ShpFile, 37, 范围框
Put #ShxFile, 37, 范围框
Close
Next
Workbooks("Shape转换标准样本").Close
End Sub
'整理多段线的坐标数组,调整节点的方向:外环为顺时针、内环为逆时针;取4位小数(ArcMap中只接收4位小数)
Public Function 面Points(Plobj As AcadEntity, 环序 As Long, R点数 As Long) As Double()
Dim Mxy As Variant
Dim 方向 As Integer, 坐标序 As Integer
Dim ShpPoints() As Double
On Error Resume Next
方向 = Sgn(Shp多边形面积(Plobj)) '负号函数
坐标序 = IIf(环序 = 1, 方向, -1 * 方向)
Dim i As Integer, J As Integer, r As Integer, N As Integer
r = IIf(Plobj.ObjectName = "AcDbPolyline", 2, 3)
Mxy = Plobj.Coordinates
N = Int(UBound(Mxy) / r) '原编号从0开始的点数
R点数 = N + 2 '编号从1开始,回到第一点的点数
ReDim ShpPoints(N * 2 + 3) '编号从0开始,回到第一点的坐标个数
If 坐标序 = 1 Then '正向
J = 0
For i = 0 To N
ShpPoints(J) = Format(Mxy(i * r), "0.0000")
ShpPoints(J + 1) = Format(Mxy(i * r + 1), "0.0000")
J = J + 2
Next
ShpPoints(J) = Format(Mxy(0), "0.0000")
ShpPoints(J + 1) = Format(Mxy(1), "0.0000")
Else '反向
ShpPoints(0) = Format(Mxy(0), "0.0000")
ShpPoints(1) = Format(Mxy(1), "0.0000")
J = 2
For i = N To 0 Step -1
ShpPoints(J) = Format(Mxy(i * r), "0.0000")
ShpPoints(J + 1) = Format(Mxy(i * r + 1), "0.0000")
J = J + 2
Next
End If
面Points = ShpPoints
End Function
Sub Shape面记录内容(Entry As AcadEntity)
Dim longP As Long
Dim Obj小 As Variant, Obj大 As Variant
Dim 环指针 As Long, 环数 As Long, 环序 As Long
Dim 点数 As Long, 点序 As Long
Dim 记录指针 As Long
Dim Offset As Long, longN As Long
Dim loopObj As AcadEntity
Dim N As Integer
Dim ShpPoints() As Double
On Error Resume Next
Entry.GetBoundingBox Obj小, Obj大
图形框(0) = Format(Obj小(0), "0.000")
图形框(1) = Format(Obj小(1), "0.000")
图形框(2) = Format(Obj大(0), "0.000")
图形框(3) = Format(Obj大(1), "0.000")
范围框(0) = IIf(图形框(0) < 范围框(0), 图形框(0), 范围框(0))
范围框(1) = IIf(图形框(1) < 范围框(1), 图形框(1), 范围框(1))
范围框(2) = IIf(图形框(2) > 范围框(2), 图形框(2), 范围框(2))
范围框(3) = IIf(图形框(3) > 范围框(3), 图形框(3), 范围框(3))
'记录头 大端序《记录条数,记录长度》
Put #ShpFile, Shp指针, 转为大端序(记录条数) '记录编号
记录指针 = Shp指针 + 4 '图形输出结束后补输出记录长度
Shp指针 = Shp指针 + 8
'记录内容
Put #ShpFile, Shp指针, 5 '记录类型
Shp指针 = Shp指针 + 4
Put #ShpFile, Shp指针, 图形框: Shp指针 = Shp指针 + 32 '图形边界合:x小、y小、大、y大
Select Case Entry.ObjectName
Case "AcDbHatch"
Dim MyHatch As New Collection
Set MyHatch = 填充图案的环PR(Entry)
环数 = MyHatch.Count
Put #ShpFile, Shp指针, 环数 '环数
'总点数在后面补写
环指针 = Shp指针 + 4
Shp指针 = Shp指针 + 环数 * 4 + 8
点数 = 0: 点序 = 0: 环序 = 1 '总点数、各环的起点编号
For Each loopObj In MyHatch
Put #ShpFile, 环指针 + 4 * 环序, 点序 '点序
ShpPoints = 面Points(loopObj, 环序, 点数) '获取多段线的坐标数组
点序 = 点序 + 点数
环序 = 环序 + 1
Put #ShpFile, Shp指针, ShpPoints: Shp指针 = Shp指针 + 点数 * 16
Next
Put #ShpFile, 环指针, 点序 '补写总点数
Case "AcDb2dPolyline", "AcDbPolyline", "AcDbWlPolyline", "AcDb3dPolyline"
ShpPoints = 面Points(Entry, 1, 点数) '获取多段线的坐标数组
Put #ShpFile, Shp指针, 1: Shp指针 = Shp指针 + 4 '环数=1
Put #ShpFile, Shp指针, 点数: Shp指针 = Shp指针 + 4 '总点数
Put #ShpFile, Shp指针, 0: Shp指针 = Shp指针 + 4 '环序=0
Put #ShpFile, Shp指针, ShpPoints: Shp指针 = Shp指针 + 点数 * 16
End Select
记录长度 = Shp指针 - 记录长度 - 8
Put #ShpFile, 记录指针, 转为大端序(记录长度) '当前记录要素的记录长度
Offset = 记录指针 - 5
longN = 转为大端序(Offset)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
longN = 转为大端序(记录长度)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
记录长度 = Shp指针
Put #DbfFile, Dbf指针, 32
Dbf指针 = Dbf指针 + 1
For N = 0 To 字段数 - 1
Put #DbfFile, Dbf指针, pField(N).Name
Dbf指针 = Dbf指针 + pField(N).Length
Next
End Sub
Public Function Shp多边形面积(Plobj As AcadEntity) As Double '当面积为正值,多边形为顺时针;当面积为负值,多边形为逆时针。
Dim N As Long, i As Long, J As Long, r As Integer
Dim 面积 As Double
On Error Resume Next
xy = Plobj.Coordinates
r = IIf(Plobj.ObjectName = "AcDbPolyline", 2, 3)
N = Int(UBound(xy) / r)
For i = 0 To N
J = IIf(i = N, 0, i + 1)
面积 = 面积 + xy(i * r) * xy(J * r + 1) - xy(i * r + 1) * xy(J * r)
Next i
Shp多边形面积 = -1 * 面积 / 2
End Function
Sub Shape点记录内容(PointObj As AcadEntity)
Dim longP As Long, N As Integer
Dim Offset As Long, longN As Long
Dim xy As Variant
Dim ShpPoints(0 To 1) As Double
Select Case PointObj.ObjectName
Case "AcDbText"
xy = PointObj.InsertionPoint
Case "AcDbBlockReference"
xy = PointObj.InsertionPoint
Case "AcDbPoint"
xy = PointObj.Coordinates
Case "AcDbCircle"
xy = PointObj.Center
End Select
ShpPoints(0) = xy(0)
ShpPoints(1) = xy(1)
范围框(0) = IIf(ShpPoints(0) < 范围框(0), ShpPoints(0), 范围框(0))
范围框(1) = IIf(ShpPoints(1) < 范围框(1), ShpPoints(1), 范围框(1))
范围框(2) = IIf(ShpPoints(0) > 范围框(2), ShpPoints(0), 范围框(2))
范围框(3) = IIf(ShpPoints(1) > 范围框(3), ShpPoints(1), 范围框(3))
'记录头 大端序《记录条数,记录长度》
Offset = Shp指针 - 1
Put #ShpFile, Shp指针, 转为大端序(记录条数): Shp指针 = Shp指针 + 4 '记录条数
Put #ShpFile, Shp指针, 转为大端序(20): Shp指针 = Shp指针 + 4 '记录长度:点的记录长度固定=20
'记录内容
Put #ShpFile, Shp指针, 1: Shp指针 = Shp指针 + 4 '记录类型
Put #ShpFile, Shp指针, ShpPoints: Shp指针 = Shp指针 + 16
longN = 转为大端序(Offset)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
longN = 转为大端序(20)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
Put #DbfFile, Dbf指针, 32
Dbf指针 = Dbf指针 + 1
For N = 0 To 字段数 - 1
Put #DbfFile, Dbf指针, pField(N).Name
Dbf指针 = Dbf指针 + pField(N).Length
Next
End Sub
Sub Shape线记录内容(Plobj As AcadEntity)
Dim longP As Long, N As Integer
Dim Offset As Long, longN As Long
Dim 点数 As Long, 线数 As Long
Dim X As Double
Dim ShpPoints() As Double
Dim Obj小 As Variant, Obj大 As Variant
ShpPoints = 线Points(Plobj) '获取多段线的节点坐标
线数 = 1
点数 = (UBound(ShpPoints) + 1) / 2
记录长度 = 44 + 线数 * 4 + 点数 * 16
Plobj.GetBoundingBox Obj小, Obj大
图形框(0) = Format(Obj小(0), "0.000")
图形框(1) = Format(Obj小(1), "0.000")
图形框(2) = Format(Obj大(0), "0.000")
图形框(3) = Format(Obj大(1), "0.000")
范围框(0) = IIf(图形框(0) < 范围框(0), 图形框(0), 范围框(0))
范围框(1) = IIf(图形框(1) < 范围框(1), 图形框(1), 范围框(1))
范围框(2) = IIf(图形框(2) > 范围框(2), 图形框(2), 范围框(2))
范围框(3) = IIf(图形框(3) > 范围框(3), 图形框(3), 范围框(3))
'记录头 大端序《记录条数,记录长度》
Offset = Shp指针 - 1
Put #ShpFile, Shp指针, 转为大端序(记录条数): Shp指针 = Shp指针 + 4 '记录条数
Put #ShpFile, Shp指针, 转为大端序(记录长度): Shp指针 = Shp指针 + 4 '记录长度:线点的记录长度=52 + 线数 * 4 + 点数 * 16
'记录内容
Put #ShpFile, Shp指针, 3: Shp指针 = Shp指针 + 4 '记录类型
Put #ShpFile, Shp指针, 图形框: Shp指针 = Shp指针 + 32 '坐标范围(Box)
Put #ShpFile, Shp指针, 线数: Shp指针 = Shp指针 + 4 '线段的个数
Put #ShpFile, Shp指针, 点数: Shp指针 = Shp指针 + 4 '顶点个数
Put #ShpFile, Shp指针, 0: Shp指针 = Shp指针 + 4 '坐标点在Points的位置
Put #ShpFile, Shp指针, ShpPoints: Shp指针 = Shp指针 + 点数 * 16
longN = 转为大端序(Offset)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
longN = 转为大端序(记录长度)
Put #ShxFile, Shx指针, longN: Shx指针 = Shx指针 + 4
Put #DbfFile, Dbf指针, 32
Dbf指针 = Dbf指针 + 1
For N = 0 To 字段数 - 1
Put #DbfFile, Dbf指针, pField(N).Name
Dbf指针 = Dbf指针 + pField(N).Length
Next
End Sub
'整理多段线的节点坐标
Public Function 线Points(Plobj As AcadEntity) As Double()
Dim xy As Variant
Dim i As Integer, J As Integer, r As Integer
Dim ShpPoints() As Double
Select Case Plobj.ObjectName
Case "AcDbPolyline"
xy = Plobj.Coordinates
r = 2
Case "AcDb2dPolyline"
xy = Plobj.Coordinates
r = 3
Case "AcDbLine"
ReDim ShpPoints(3)
xy = Plobj.StartPoint
ShpPoints(0) = xy(0)
ShpPoints(1) = xy(1)
xy = Plobj.EndPoint
ShpPoints(2) = xy(0)
ShpPoints(3) = xy(1)
GoTo 20
End Select
J = Int(UBound(xy) / r)
ReDim ShpPoints(J * 2 + 1)
For i = 0 To J
ShpPoints(i * 2) = Format(xy(i * r), "0.0000")
ShpPoints(i * 2 + 1) = Format(xy(i * r + 1), "0.0000")
Next
20: 线Points = ShpPoints
End Function
Function 投影文件(坐标系 As String, 加带号 As Boolean, 中央子午线 As Double, 投影带宽 As Integer) As String
Dim str1 As String, str2 As String
Dim 投影项目 As String 'PROJCS["CGCS2000_3_Degree_GK_Zone_39",
Dim 地理标志 As String 'GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",
Dim 基准 As String 'DATUM["D_China_2000",
Dim 球体 As String 'SPHEROID["CGCS2000",6378137.0,298.257222101]],
Dim 加常数 As String 'PARAMETER["False_Easting",39500000.0], '加常数
Dim 中央径线 As String 'PARAMETER["Central_Meridian",117.0], '中央子午线
Dim 常数 As Long
中央径线 = "PARAMETER[" & Chr(34) & "Central_Meridian" & Chr(34) & Chr(44) & Format(中央子午线, "0.0") + "]" & Chr(44)
Select Case 坐标系
Case "2000国家大地坐标系"
str1 = "PROJCS[" & Chr(34) & "CGCS2000_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_China_Geodetic_Coordinate_System_2000" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_China_2000" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "CGCS2000" & Chr(34) & ",6378137.0,298.257222101]],"
'"2000 国家大地坐标系", "CGCS2000", 6378137, 6356752.31414 '1/298.257222101
Case "1980西安坐标系"
str1 = "PROJCS[" & Chr(34) & "Xian_1980_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_Xian_1980" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_Xian_1980" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "Xian_1980" & Chr(34) & ",6378140.0,298.257]],"
'"1975年椭球", "XA1980",6378140, 6356755.2882 '298.257
Case "1954年北京坐标系"
str1 = "PROJCS[" & Chr(34) & "Beijing_1954_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_Beijing_1954" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_Beijing_1954" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "Beijing_1954" & Chr(34) & ",6378245.0,298.3]],"
'"克拉索夫斯基椭球", "BJ1954", 6378245, 6356863.0188 '298.3
Case "WGS_1984坐标系"
str1 = "PROJCS[" & Chr(34) & "WGS_1984_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_WGS_1984" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_WGS_1984" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "WGS_1984" & Chr(34) & ",6378137.0,298.257223563]],"
'"WGS84椭球", "WGS84", 6378137, 6356752.3142 '298.257223563
End Select
Select Case 投影带宽
Case 3
Select Case 加带号
Case True
常数 = 中央子午线 / 3
投影项目 = str1 + "3_Degree_GK_Zone_" + Trim(常数) & Chr(34) & Chr(44) '"Beijing_1954_3_Degree_GK_Zone_39" "Xian_1980_3_Degree_GK_Zone_39"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & Format(常数 * 1000000 + 500000, "0.0") & "],"
Case False
投影项目 = str1 + "3_Degree_GK_CM_" + Trim(中央子午线) + "E" & Chr(34) & Chr(44) '"Beijing_1954_3_Degree_GK_CM_117E" "Xian_1980_3_Degree_GK_CM_117E"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & "500000.0],"
End Select
Case 6
Select Case 加带号
Case True
常数 = 中央子午线 / 6
投影项目 = str1 + "GK_Zone_" + Trim(常数) & Chr(34) & Chr(44) '"Beijing_1954_GK_Zone_20" "CGCS2000_GK_Zone_20" "Xian_1980_GK_Zone_20"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & Format(常数 * 1000000 + 500000, "0.0") & "],"
Case False
投影项目 = str1 + "GK_CM_" + Trim(中央子午线) + "E" & Chr(34) & Chr(44) '"CGCS2000_GK_CM_117E" "Xian_1980_GK_CM_117E"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & "500000.0],"
End Select
End Select
Dim m(0 To 12) As String
m(0) = 投影项目
m(1) = 地理标志
m(2) = 基准
m(3) = 球体
m(4) = "PRIMEM[" & Chr(34) & "Greenwich" & Chr(34) & ",0.0]," '径线起点 格林威治"
m(5) = "UNIT[" & Chr(34) & "Degree" & Chr(34) & ",0.0174532925199433]]," '弧度单位
m(6) = "PROJECTION[" & Chr(34) & "Gauss_Kruger" & Chr(34) & "]," '投影
m(7) = 加常数
m(8) = "PARAMETER[" & Chr(34) & "False_Northing" & Chr(34) & ",0.0]," '北纬
m(9) = 中央径线
m(10) = "PARAMETER[" & Chr(34) & "Scale_Factor" & Chr(34) & ",1.0]," '长度比例
m(11) = "PARAMETER[" & Chr(34) & "Latitude_Of_Origin" & Chr(34) & ",0.0]," '纬度起点
m(12) = "UNIT[" & Chr(34) & "Meter" & Chr(34) & ",1.0]]" '长度单位(米)
Dim PrjName As String
PrjName = VBApath + "空间参考.prj"
Open PrjName For Output As #1
Print #1, m(0) + m(1) + m(2) + m(3) + m(4) + m(5) + m(6) + m(7) + m(8) + m(9) + m(10) + m(11) + m(12)
Close
投影文件 = PrjName
End Function
Function 投影文件(坐标系 As String, 加带号 As Boolean, 中央子午线 As Double, 投影带宽 As Integer) As String
Dim str1 As String, str2 As String
Dim 投影项目 As String 'PROJCS["CGCS2000_3_Degree_GK_Zone_39",
Dim 地理标志 As String 'GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",
Dim 基准 As String 'DATUM["D_China_2000",
Dim 球体 As String 'SPHEROID["CGCS2000",6378137.0,298.257222101]],
Dim 加常数 As String 'PARAMETER["False_Easting",39500000.0], '加常数
Dim 中央径线 As String 'PARAMETER["Central_Meridian",117.0], '中央子午线
Dim 常数 As Long
中央径线 = "PARAMETER[" & Chr(34) & "Central_Meridian" & Chr(34) & Chr(44) & Format(中央子午线, "0.0") + "]" & Chr(44)
Select Case 坐标系
Case "2000国家大地坐标系"
str1 = "PROJCS[" & Chr(34) & "CGCS2000_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_China_Geodetic_Coordinate_System_2000" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_China_2000" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "CGCS2000" & Chr(34) & ",6378137.0,298.257222101]],"
'"2000 国家大地坐标系", "CGCS2000", 6378137, 6356752.31414 '1/298.257222101
Case "1980西安坐标系"
str1 = "PROJCS[" & Chr(34) & "Xian_1980_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_Xian_1980" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_Xian_1980" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "Xian_1980" & Chr(34) & ",6378140.0,298.257]],"
'"1975年椭球", "XA1980",6378140, 6356755.2882 '298.257
Case "1954年北京坐标系"
str1 = "PROJCS[" & Chr(34) & "Beijing_1954_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_Beijing_1954" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_Beijing_1954" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "Beijing_1954" & Chr(34) & ",6378245.0,298.3]],"
'"克拉索夫斯基椭球", "BJ1954", 6378245, 6356863.0188 '298.3
Case "WGS_1984坐标系"
str1 = "PROJCS[" & Chr(34) & "WGS_1984_"
地理标志 = "GEOGCS[" & Chr(34) & "GCS_WGS_1984" & Chr(34) & Chr(44)
基准 = "DATUM[" & Chr(34) & "D_WGS_1984" & Chr(34) & Chr(44)
球体 = "SPHEROID[" & Chr(34) & "WGS_1984" & Chr(34) & ",6378137.0,298.257223563]],"
'"WGS84椭球", "WGS84", 6378137, 6356752.3142 '298.257223563
End Select
Select Case 投影带宽
Case 3
Select Case 加带号
Case True
常数 = 中央子午线 / 3
投影项目 = str1 + "3_Degree_GK_Zone_" + Trim(常数) & Chr(34) & Chr(44) '"Beijing_1954_3_Degree_GK_Zone_39" "Xian_1980_3_Degree_GK_Zone_39"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & Format(常数 * 1000000 + 500000, "0.0") & "],"
Case False
投影项目 = str1 + "3_Degree_GK_CM_" + Trim(中央子午线) + "E" & Chr(34) & Chr(44) '"Beijing_1954_3_Degree_GK_CM_117E" "Xian_1980_3_Degree_GK_CM_117E"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & "500000.0],"
End Select
Case 6
Select Case 加带号
Case True
常数 = 中央子午线 / 6
投影项目 = str1 + "GK_Zone_" + Trim(常数) & Chr(34) & Chr(44) '"Beijing_1954_GK_Zone_20" "CGCS2000_GK_Zone_20" "Xian_1980_GK_Zone_20"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & Format(常数 * 1000000 + 500000, "0.0") & "],"
Case False
投影项目 = str1 + "GK_CM_" + Trim(中央子午线) + "E" & Chr(34) & Chr(44) '"CGCS2000_GK_CM_117E" "Xian_1980_GK_CM_117E"
加常数 = "PARAMETER[" & Chr(34) & "False_Easting" & Chr(34) & Chr(44) & "500000.0],"
End Select
End Select
Dim m(0 To 12) As String
m(0) = 投影项目
m(1) = 地理标志
m(2) = 基准
m(3) = 球体
m(4) = "PRIMEM[" & Chr(34) & "Greenwich" & Chr(34) & ",0.0]," '径线起点 格林威治"
m(5) = "UNIT[" & Chr(34) & "Degree" & Chr(34) & ",0.0174532925199433]]," '弧度单位
m(6) = "PROJECTION[" & Chr(34) & "Gauss_Kruger" & Chr(34) & "]," '投影
m(7) = 加常数
m(8) = "PARAMETER[" & Chr(34) & "False_Northing" & Chr(34) & ",0.0]," '北纬
m(9) = 中央径线
m(10) = "PARAMETER[" & Chr(34) & "Scale_Factor" & Chr(34) & ",1.0]," '长度比例
m(11) = "PARAMETER[" & Chr(34) & "Latitude_Of_Origin" & Chr(34) & ",0.0]," '纬度起点
m(12) = "UNIT[" & Chr(34) & "Meter" & Chr(34) & ",1.0]]" '长度单位(米)
Dim PrjName As String
PrjName = VBApath + "空间参考.prj"
Open PrjName For Output As #1
Print #1, m(0) + m(1) + m(2) + m(3) + m(4) + m(5) + m(6) + m(7) + m(8) + m(9) + m(10) + m(11) + m(12)
Close
投影文件 = PrjName
End Function
5.3窗体
Private Sub CommandButton1_Click()
坐标系 = ComboBox1.Text
中央子午线 = TextBox1.Value
加带号 = CheckBox1.Value
Unload Me
End Sub
Private Sub OptionButton1_Click()
投影带宽 = 3
End Sub
Private Sub OptionButton2_Click()
投影带宽 = 6
End Sub
Private Sub UserForm_Initialize()
ComboBox1.AddItem "2000国家大地坐标系"
ComboBox1.AddItem "1980西安坐标系"
ComboBox1.AddItem "1954年北京坐标系"
ComboBox1.AddItem "WGS_1984坐标系"
ComboBox1.ListIndex = 0
投影带宽 = 3
加带号 = True
End Sub
'其中:CGCS2000_3_Degree_GK_Zone_38 4526 '横坐标前加带号
'CGCS2000_3_Degree_GK_Zone_39 4527 '横坐标前加带号
'CGCS2000_3_Degree_GK_Zone_40 4528 '横坐标前加带号
'CGCS2000_GK_CM_117E 4509 '横坐标前不加带号
'CGCS2000_GK_CM_123E 4510 '横坐标前不加带号
Private Sub CommandButton1_Click()
坐标系 = ComboBox1.Text
中央子午线 = TextBox1.Value
加带号 = CheckBox1.Value
Unload Me
End Sub
Private Sub OptionButton1_Click()
投影带宽 = 3
End Sub
Private Sub OptionButton2_Click()
投影带宽 = 6
End Sub
Private Sub UserForm_Initialize()
ComboBox1.AddItem "2000国家大地坐标系"
ComboBox1.AddItem "1980西安坐标系"
ComboBox1.AddItem "1954年北京坐标系"
ComboBox1.AddItem "WGS_1984坐标系"
ComboBox1.ListIndex = 0
投影带宽 = 3
加带号 = True
End Sub
'其中:CGCS2000_3_Degree_GK_Zone_38 4526 '横坐标前加带号
'CGCS2000_3_Degree_GK_Zone_39 4527 '横坐标前加带号
'CGCS2000_3_Degree_GK_Zone_40 4528 '横坐标前加带号
'CGCS2000_GK_CM_117E 4509 '横坐标前不加带号
'CGCS2000_GK_CM_123E 4510 '横坐标前不加带号
以上资料搜集自网络,版权归原作者。