用C读取DXF文件.docx
- 文档编号:23484894
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:21
- 大小:22.72KB
用C读取DXF文件.docx
《用C读取DXF文件.docx》由会员分享,可在线阅读,更多相关《用C读取DXF文件.docx(21页珍藏版)》请在冰豆网上搜索。
用C读取DXF文件
用C读取DXF文件
Author:
eryar@
摘要:
本文简要介绍了一下DXF文件的组成。
重点讲述了怎样使用C语言来读取DXF文件中的实体信息。
关键字:
C、DXF
Abstract:
ThepaperpresentthebasicpartsofDXFfile.AndfocusonhowtouseCreadtheentity’sinformationfromDXFfile.
KeyWords:
C,DXF
DXF是DrawingeXchangeFile的缩写,意思为图形交换文件,在工程制图中有广泛的应用,掌握了DXF文件的读写对编写CAD软件时的图形信息的交换有重要意义。
它有两种格式:
一种是ASCIIDXF格式;一种是二进制DXF格式。
ASCIIDXF文件格式是ASCII文字格式的AutoCAD图形的完整表示,这种文件格式易于被其它程序处理。
二进制格式的DXF文件与ASCII格式的DXF文件包含的信息相同,但格式上二进制格式比ASCII格式更精简,能够节省百分之二十五的文件空间。
AutoCAD能够更快地对其执行读写操作(通常能快五倍)。
这可能是对ASCII格式的DXF文件操作时有ASCII与二进制形式的转换,因而花费时间较多。
本文主要讨论ASCII格式的DXF文件,因为它可读性强。
一、ASCII格式的DXF文件的组成
先来介绍一下ASCII格式的DXF文件的组成。
(小提示:
打开AutoCAD,新建一个空的文件,然后再输出为DXF文件,并用记事本打开DXF文件,就可以看到它的所有代码了,这样有助于你更好地理解DXF文件的组成。
还有按一下F1,打开AutoCAD的帮助文件,找到DXF参考,它是权威具体的资料。
)
用记事本打开一个DXF文件,你可以发现它里面有这样一些代码:
0
SECTION
2
HEADER
9
$ACADVER
1
AC1015
……
即里面总是数字和字符串/数字在交替的出现。
数字就叫做代码(通常称为组码),紧跟组码数字的称为关联值对。
(以下内容来自DXF参考)DXF文件本质上由代码及关联值对组成。
代码(通常称为组码)表明其后的值的类型。
使用这些组码和值对,可以将DXF文件组织到由记录组成的区域中,这些记录由组码和数据项目组成。
在DXF文件,每个组码和值各占一行。
表1为组码值类型表的部分:
表1组码值类型表(部分)
一个完整的ASCII格式的DXF文件结构如下:
●HEADER段。
它包含图形的基本信息。
它由AutoCAD数据库版本号和一些系统变量组成。
每个参数都包含一个变量名称及其关联的值。
●CLASSES段。
包含应用程序定义的类的信息,这些类的实例出现在数据库的BLOCKS、ENTITIES和OBJECTS段中。
类定义在类的层次结构中是固定不变的。
●TABLES段。
包含以下符号表的定义:
APPID(应用程序标识表)
BLOCK_RECORD(块参照表)
DIMSTYLE(标注样式表)
LAYER(图层表)
LTYPE(线型表)
STYLE(文字样式表)
UCS(用户坐标系表)
VIEW(视图表)
VPORT(视口配置表)
●BLOCKS段。
包含构成图形中每个块参照的块定义和图形图元。
●ENTITIES段。
包含图形中的图形对象(图元),其中包括块参照(插入图元)。
这里的信息很重要。
●OBJECTS段。
包含图形中的非图形对象。
除图元、符号表记录以及符号表以外的所有对象都存储在此段。
OBJECTS段中的条目样例是包含多线样式和组的词典。
●THUMBNAILIMAGE段。
包含图形的预览图像数据。
此段为可选。
每个段都以一个后跟字符串SECTION的组码0开始,其后是组码2和表示该段名称的字符串(例如,HEADER)。
每个段都由定义其元素的组码和值组成。
每个段都以一个后跟字符串ENDSEC的组码0结束。
举两个例子:
1.以下是DXF™文件HEADER段的样例:
0HEADER段的开始
SECTION
2
HEADER
9每出现一个标题变量便重复一次
$<变量>
<组码>
<值>
0HEADER段的结尾
ENDSEC
2.以下是DXF文件ENTITIES段的样例:
0ENTITIES段的开始
SECTION
2
ENTITIES
0每个图元定义有一个条目,如LINE,CIRCLE
<图元类型>
5
<句柄>
330
<指向所有者的指针>
100
AcDbEntity
8
<图层>
100
AcDb<类名>
.
.<数据>
.
0ENTITIES段的结尾
ENDSEC
因此你需要什么信息就可以在相应的段中寻找。
例如你需要得到DXF文件的版本信息就可在HEADER段中寻找。
需要图形的信息就可到ENTITIES段中寻找。
再强调一下实体段:
实体段记录了除块段出现的实体以外的所有绘图实体内容,包括每个实体的名称、所在图层、线型、颜色代码等等。
由于定义一个实体所有组码在某一实体的任意组码在其值与默认值相同时可以省略不写。
因此用户在读取DXF文件时应注意:
1.定义一个实体的数据是以“0”组码开始,而以另一个“0”组码的出现表示结束;
2.某一实体的定义数据顺序不固定。
因此用户在编写DXF文件处理程序时不能按顺序固定的格式处理,而只能按组码的同现来记录数据。
二、读取DXF文件流程
有了以上知识就可读懂DXF文件并从中提取我们所需要的信息了,而我们所需要的信息大多在ENTITIES段中。
先讲一下大概的处理方法。
输入DXF文件名
打开DXF文件
读取一个记录
HEADER
TABLES
ENTITIES
BLOCKS
EOF
处理HEADER
处理TABLES
处理ENTITIES
处理BLOCKS
结束
图2DXF文件处理流程
如图2所示为DXF文件处理流程。
可以从DXF文件中检索,当检索到与某个段时就转到那个段的处理程序去处理。
如检索到HEADER段就转入HEADER段的处理程序去处理。
图形的大部分信息都在实体ENTITIES段中,因此读取实体段的内容很重要。
读取实体段的数据首先要考虑读取数据的存储方式,然后再进行后一步的处理或存入数据文件中。
此处用链表结构来存储。
各个实体的数据分成两块:
公共数据块和特殊数据块。
公共数据块存储每个实体都具有特征参数,如所在图层,实体标识,线型名……
特殊数据块存储每个实体特有的数据,如实体LINE,它里面有两个端点的坐标值;实体CIRCLE中有圆心坐标值和半径值等。
单个实体的数据处理方法:
读取一个实体的数据首先根据组码“0”后的实体标识字符串来确定其为哪一种实体,然后再根据这个实体的具体情况来读取数据。
下面为用C具体实现的代码。
因为是处理ASCII文件,只需要用到C文件处理的两个标准函数:
fprintf()和fscanf()。
文件中有一个位置指针,指向当前读写位置。
如果顺序读写一个文件,每次读写完一个字符后,该指针自动指向下一个字符的位置。
三、读取DXF文件信息的小程序
先来看一个用C来读取HEADER段中的版本号的小程序。
viewplaincopytoclipboardprint?
1./*--------------------------------------------------
2.
3.*Header.C
4.
5.*读取DXF文件中HEADER段中DXF文件版本号的小程序。
6.
7.*eryar@02-05-0818:
55
8.
9.*----------------------------------------------------*/
10.
11.
12.
13.
14.
15.#include
16.
17.#include
18.
19.#include
20.
21.
22.
23.#defineSTRLEN30
24.
25.
26.
27.intmain(intargc,char*argv[])
28.
29.{
30.
31.intcode;/*存储组码*/
32.
33.charcodevalue[STRLEN];/*存储组码对应的值*/
34.
35.FILE*dxf;/*文件指针*/
36.
37.charfilename[STRLEN];/*文件名*/
38.
39.charsuffix[6]=".dxf";/*只输入文件名打开DXF文件,不用输后缀.*/
40.
41.
42.
43.printf("请输入文件名:
");
44.
45.gets(filename);
46.
47.strcat(filename,suffix);
48.
49.
50.
51.dxf=fopen(filename,"r");/*打开文件进行读操作*/
52.
53.if(!
dxf){
54.
55.printf("打开文件出错!
/n按任意键退出...");
56.
57.getch();
58.
59.exit(0);
60.
61.}
62.
63.else{
64.
65.printf("文件已经打开./n正在读取.../n");
66.
67.}
68.
69.
70.
71.while(!
feof(dxf)){
72.
73.fscanf(dxf,"%d",&code);
74.
75.fscanf(dxf,"%s",codevalue);
76.
77.
78.
79.if(code==2&&strcmp(codevalue,"HEADER")==0)
80.{
81.fscanf(dxf,"%d",&code);
82.
83.fscanf(dxf,"%s",codevalue);
84.
85.if(strcmp(codevalue,"$ACADVER")==0)
{
86.
87.fscanf(dxf,"%d",&code);
88.
89.fscanf(dxf,"%s",codevalue);
90.
91.
92.
93.if(strcmp(codevalue,"AC1006")==0){
94.
95.printf("AutoCAD版本为R10.");
96.
97.}
98.
99.elseif(strcmp(codevalue,"AC1009")==0){
100.
101.printf("AutoCAD版本为R11和R12.");
102.
103.}
104.
105.elseif(strcmp(codevalue,"AC1012")==0){
106.printf("AutoCAD版本为R13.");
107.
108.}
109.
110.elseif(strcmp(codevalue,"AC1014")==0){
111.
112.printf("AutoCAD版本为R14.");
113.
114.}
115.
116.elseif(strcmp(codevalue,"AC1015")==0){
117.
118.printf("AutoCAD版本为AutoCAD2000.");
119.
120.}
121.
122.elseif(strcmp(codevalue,"AC1018")==0){
123.
124.printf("AutoCAD版本为AutoCAD2004.");
125.
126.}
127.
128.else{
129.
130.printf("不能识别的AutoCAD版本!
");
131.
132.break;
133.
134.}
135.
136.}
137.}
138.
139.}
140.
141.
142.
143.fclose(dxf);/*关闭文件*/
144.
145.printf("/n文件已经关闭.");
146.
147.printf("/nPressanykeytohalt...");
148.
149.getch();
150.
151.}
上述代码为打开一个DXF文件后就顺序读取只到文件结束,当遇到组码为2且组码对应的组值为字符串“HEADER”时就对HEADER段进行处理。
在HEADER段中,若遇到组值“$ACADVER”时,则下一个组码对应的值就为AutoCAD的版本信息。
具体版本信息可参考AutoCAD帮助文件DXF参考中的HEADER段->HEADER段组码部分。
若对理解了上述程序后,就可以读取DXF文件中实体ENTITIES部分的有用的数据了。
首先要确定实体的数据结构。
下面的代码为实体数据结构的定义,你也可以根据需要扩展这些实体的内容。
程序的主要思路来自参考文献2。
#defineSTRLEN60
#defineDATASIZEsizeof(EntityData)
/*-----每个实体的结构-----*/
//你可在在此添加其它的实体
//为了提高精度,变量可定义为双精度型
typedefstructtagLine{
floatx1,y1,z1;
floatx2,y2,z2;
}LINE;
typedefstructtagCircle{
floatx,y,z;
floatradius;
}CIRCLE;//给tagcircle起个别名叫circle
/*------------------------*/
typedefunionspecialData{
LINEline;
CIRCLEcircle;
}privateData;
/*------实体的数据结构-------*/
typedefstructcommonData{
charid[STRLEN];/*实体标识字符串*/
charlayer[STRLEN];/*层名字符串*/
privateDatadata;/*特有数据块*/
structcommonData*next;/*用于构建链表*/
}EntityData;
定义完数据结构后,就可以用链表结构来存储实体中有用的信息了。
以下程序为读取实体LINE的有关信息的代码。
/*------------------------------------------
*Entity.C读取实体LINE部分内容。
*eryar@02-05-0819:
52
*-------------------------------------------*/
#include
#include
#include
#include
#defineSTRLEN60
#defineDATASIZEsizeof(EntityData)
/*-----每个实体的结构-----*/
//你可在在此添加其它的实体
typedefstructtagLine{
floatx1,y1,z1;
floatx2,y2,z2;
}LINE;
typedefstructtagCircle{
floatx,y,z;
floatradius;
}CIRCLE;
/*------------------------*/
typedefunionspecialData{
LINEline;
CIRCLEcircle;
}privateData;
typedefstructcommonData{
charid[STRLEN];/*实体标识字符串*/
charlayer[STRLEN];/*层名字符串*/
privateDatadata;/*特有数据块*/
structcommonData*next;/*用于构建链表*/
}EntityData;
/*----------函数声明部分-----------*/
voidprint(EntityData*entity);
/*---------------------------------*/
intmain(intargc,char*argv[])
{
intcode;
floatvalue;
charcodevalue[STRLEN];
FILE*dxf;
charfilename[STRLEN];
charsuffix[6]=".dxf";
EntityData*entity,*entity1,*entity2;
printf("请输入DXF文件名:
");
gets(filename);
strcat(filename,suffix);
dxf=fopen(filename,"r");
if(!
dxf){
printf("打开文件出错!
/n可能不存在此文件./n");
printf("按任意键退出...");
getch();
exit(0);
}
else{
printf("正在读取文件.../n");
}
entity=entity2=(EntityData*)malloc(DATASIZE);
while(!
feof(dxf)){
fscanf(dxf,"%d",&code);
fscanf(dxf,"%s",codevalue);
if(code==2&&strcmp(codevalue,"ENTITIES")==0){
while(strcmp(codevalue,"ENDSEC")){
fscanf(dxf,"%d",&code);
fscanf(dxf,"%s",codevalue);
if(code==0&&strcmp(codevalue,"LINE")==0){
entity1=(EntityData*)malloc(DATASIZE);
strcpy(entity1->id,codevalue);
fscanf(dxf,"%d",&code);
while(code){
switch(code){
case8:
fscanf(dxf,"%s",codevalue);
fscanf(dxf,"%d",&code);
strcpy(entity1->layer,codevalue);
break;
case10:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.x1=value;
break;
case20:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.y1=value;
break;
case30:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.z1=value;
break;
case11:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.x2=value;
break;
case21:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.y2=value;
break;
case31:
fscanf(dxf,"%f",&value);
fscanf(dxf,"%d",&code);
entity1->data.line.z2=value;
break;
default:
{
fscanf(dxf,"%s",codevalue);
fscanf(dxf,"%d",&code);
}
}
}
entity2->next=entity1;
entity2=entity1;
}
}
entity2->next=NULL;
}
}
entity=entity->next;//第一个实体区为空,所以使头指针移向下一个实体
print(entity);//输出链表
printf("/nPressanykeytohalt...");
getch();
return0;
}
//输出链表
voidprint(EntityData*entity)
{
inti=0;
EntityData*pointer;
pointer=entity;
if(pointer!
=NULL){
do{
i++;
pointer=pointer->next;
}while(pointer!
=NULL);
}
printf("/nOutputLinkList:
");
printf("/nDXF文件中总共有%d条直线:
/n",i);
i=1;
pointer=entity;
if(pointer!
=NULL){
do{
printf("第%d条直线:
/n",i);
printf("X1=%f/tY1=%f/tZ1=%f/n",pointer->data.line.x1,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 读取 DXF 文件