摘要:本文简要介绍了一下DXF文件的组成。重点讲述了怎样使用C语言来读取DXF文件中的实体信息。 关键字:C、DXF
Key Words: C, DXF
一、ASCII格式的DXF文件的组成 用记事本打开一个DXF文件,你可以发现它里面有这样一些代码:
0 SECTION
2 HEADER 9 $ACADVER 1 AC1015 …… 即里面总是数字和字符串/数字在交替的出现。数字就叫做代码(通常称为组码),紧跟组码数字的称为关联值对。(以下内容来自DXF参考)DXF文件本质上由代码及关联值对组成。代码(通常称为组码)表明其后的值的类型。使用这些组码和值对,可以将DXF文件组织到由记录组成的区域中,这些记录由组码和数据项目组成。在DXF文件,每个组码和值各占一行。表1为组码值类型表的部分:
l HEADER段。它包含图形的基本信息。它由AutoCAD数据库版本号和一些系统变量组成。每个参数都包含一个变量名称及其关联的值。 l CLASSES段。包含应用程序定义的类的信息,这些类的实例出现在数据库的BLOCKS、ENTITIES和OBJECTS段中。类定义在类的层次结构中是固定不变的。 l TABLES段。包含以下符号表的定义: APPID(应用程序标识表) BLOCK_RECORD(块参照表) DIMSTYLE(标注样式表) LAYER(图层表) LTYPE(线型表) STYLE(文字样式表) UCS(用户坐标系表) VIEW(视图表) VPORT(视口配置表) l BLOCKS段。包含构成图形中每个块参照的块定义和图形图元。 l ENTITIES段。包含图形中的图形对象(图元),其中包括块参照(插入图元)。这里的信息很重要。 l OBJECTS段。包含图形中的非图形对象。除图元、符号表记录以及符号表以外的所有对象都存储在此段。OBJECTS段中的条目样例是包含多线样式和组的词典。 l THUMBNAILIMAGE段。包含图形的预览图像数据。此段为可选。 每个段都以一个后跟字符串SECTION的组码0开始,其后是组码2和表示该段名称的字符串(例如,HEADER)。每个段都由定义其元素的组码和值组成。每个段都以一个后跟字符串ENDSEC的组码0结束。举两个例子: 1.以下是 DXF? 文件 HEADER 段的样例: 0 HEADER 段的开始 SECTION 2 HEADER 9 每出现一个标题变量便重复一次 $<变量> <组码> <值> 0 HEADER 段的结尾 ENDSEC
0 ENTITIES 段的开始 SECTION 2 ENTITIES 0 每个图元定义有一个条目,如LINE,CIRCLE <图元类型> 5 <句柄> 330 <指向所有者的指针> 100 AcDbEntity 8 <图层> 100 AcDb<类名> . . <数据> . 0 ENTITIES 段的结尾 ENDSEC 因此你需要什么信息就可以在相应的段中寻找。例如你需要得到DXF文件的版本信息就可在HEADER段中寻找。需要图形的信息就可到ENTITIES段中寻找。 再强调一下实体段:实体段记录了除块段出现的实体以外的所有绘图实体内容,包括每个实体的名称、所在图层、线型、颜色代码等等。由于定义一个实体所有组码在某一实体的任意组码在其值与默认值相同时可以省略不写。因此用户在读取DXF文件时应注意: 1. 定义一个实体的数据是以“0”组码开始,而以另一个“0”组码的出现表示结束; 2. 某一实体的定义数据顺序不固定。 因此用户在编写DXF文件处理程序时不能按顺序固定的格式处理,而只能按组码的同现来记录数据。 二、读取DXF文件流程
图2 DXF文件处理流程 如图2所示为DXF文件处理流程。可以从DXF文件中检索,当检索到与某个段时就转到那个段的处理程序去处理。如检索到HEADER段就转入HEADER 段的处理程序去处理。 图形的大部分信息都在实体ENTITIES段中,因此读取实体段的内容很重要。读取实体段的数据首先要考虑读取数据的存储方式,然后再进行后一步的处理或存入数据文件中。此处用链表结构来存储。 各个实体的数据分成两块:公共数据块和特殊数据块。公共数据块存储每个实体都具有特征参数,如所在图层,实体标识,线型名…… 特殊数据块存储每个实体特有的数据,如实体LINE,它里面有两个端点的坐标值;实体CIRCLE中有圆心坐标值和半径值等。 单个实体的数据处理方法:读取一个实体的数据首先根据组码“0”后的实体标识字符串来确定其为哪一种实体,然后再根据这个实体的具体情况来读取数据。 下面为用C具体实现的代码。因为是处理ASCII文件,只需要用到C文件处理的两个标准函数:fprintf()和fscanf()。文件中有一个位置指针,指向当前读写位置。如果顺序读写一个文件,每次读写完一个字符后,该指针自动指向下一个字符的位置。
/*-------------------------------------------------- * Header.C *读取DXF文件中HEADER段中DXF文件版本号的小程序。 * http://www.360doc.com/mailto:eryar@163.com 02-05-08 18:55 *----------------------------------------------------*/
#include <stdlib.h> #include <string.h>
{ int code; /*存储组码*/ char codevalue[STRLEN]; /*存储组码对应的值*/ FILE *dxf; /*文件指针*/ char filename[STRLEN]; /*文件名*/ char suffix[6] = ".dxf"; /*只输入文件名打开DXF文件,不用输后缀.*/
printf("请输入文件名:"); gets(filename); strcat(filename,suffix);
dxf = fopen(filename,"r"); /*打开文件进行读操作*/ if(!dxf) { printf("打开文件出错!\n按任意键退出..."); getch(); exit(0); } else { printf("文件已经打开.\n正在读取...\n"); }
while(!feof(dxf)) { fscanf(dxf,"%d",&code); fscanf(dxf,"%s",codevalue);
if(code == 2 && strcmp(codevalue,"HEADER")==0) { fscanf(dxf,"%d",&code); fscanf(dxf,"%s",codevalue); if(strcmp(codevalue,"$ACADVER")==0) { fscanf(dxf,"%d",&code); fscanf(dxf,"%s",codevalue);
if(strcmp(codevalue,"AC1006")==0) { printf("AutoCAD版本为R10."); } else if(strcmp(codevalue,"AC1009")==0) { printf("AutoCAD版本为R11和R12."); } else if(strcmp(codevalue,"AC1012")==0) { printf("AutoCAD版本为R13."); } else if(strcmp(codevalue,"AC1014")==0) { printf("AutoCAD版本为R14."); } else if(strcmp(codevalue,"AC1015")==0) { printf("AutoCAD版本为AutoCAD 2000."); } else if(strcmp(codevalue,"AC1018")==0) { printf("AutoCAD版本为AutoCAD 2004."); } else { printf("不能识别的AutoCAD版本!"); break; } } } }
fclose(dxf); /*关闭文件*/ printf("\n文件已经关闭."); printf("\nPress any key to halt..."); getch(); }
#define STRLEN 60 #define DATASIZE sizeof(EntityData)
//你可在在此添加其它的实体 //为了提高精度,变量可定义为双精度型 typedef struct tagLine{ float x1,y1,z1; float x2,y2,z2; }LINE;
float x,y,z; float radius; }CIRCLE; /*------------------------*/
LINE line; CIRCLE circle; }privateData; /*------实体的数据结构-------*/ typedef struct commonData{ char id[STRLEN]; /*实体标识字符串*/ char layer[STRLEN]; /*层名字符串*/ privateData data; /*特有数据块*/ struct commonData *next; /*用于构建链表*/ }EntityData; 定义完数据结构后,就可以用链表结构来存储实体中有用的信息了。以下程序为读取实体LINE的有关信息的代码。 /*------------------------------------------ *Entity.C 读取实体LINE部分内容。 http://www.360doc.com/mailto:*eryar@163.com 02-05-08 19:52 *-------------------------------------------*/
#include <conio.h> #include <stdlib.h> #include <string.h>
#define DATASIZE sizeof(EntityData)
//你可在在此添加其它的实体 typedef struct tagLine{ float x1,y1,z1; float x2,y2,z2; }LINE;
float x,y,z; float radius; }CIRCLE; /*------------------------*/
LINE line; CIRCLE circle; }privateData;
char id[STRLEN]; /*实体标识字符串*/ char layer[STRLEN]; /*层名字符串*/ privateData data; /*特有数据块*/ struct commonData *next; /*用于构建链表*/ }EntityData;
void print(EntityData *entity); /*---------------------------------*/
{ int code; float value; char codevalue[STRLEN];
FILE *dxf; char filename[STRLEN]; char suffix[6] = ".dxf";
gets(filename); strcat(filename,suffix);
if(!dxf) { printf("打开文件出错!\n可能不存在此文件.\n"); printf("按任意键退出..."); getch(); exit(0); } else { printf("正在读取文件...\n"); }
while(!feof(dxf)) { fscanf(dxf,"%d",&code); fscanf(dxf,"%s",codevalue);
while(strcmp(codevalue,"ENDSEC")) { fscanf(dxf,"%d",&code); fscanf(dxf,"%s",codevalue);
entity1 = (EntityData *)malloc(DATASIZE);
while(code) { switch(code) { case 8: fscanf(dxf,"%s",codevalue); fscanf(dxf,"%d",&code); strcpy(entity1->layer,codevalue); break; case 10: fscanf(dxf,"%f",&value); fscanf(dxf,"%d",&code); entity1->data.line.x1 = value; break; case 20: fscanf(dxf,"%f",&value); fscanf(dxf,"%d",&code); entity1->data.line.y1 = value; break; case 30: fscanf(dxf,"%f",&value); fscanf(dxf,"%d",&code); entity1->data.line.z1 = value; break; case 11: fscanf(dxf,"%f",&value); fscanf(dxf,"%d",&code); entity1->data.line.x2 = value; break; case 21: fscanf(dxf,"%f",&value); fscanf(dxf,"%d",&code); entity1->data.line.y2 = value; break; case 31: 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; } }
print(entity); //输出链表
getch(); return 0; }
void print(EntityData *entity) { int i=0; EntityData *pointer;
do{ i++; pointer = pointer->next; }while(pointer != NULL); }
printf("\nDXF文件中总共有%d条直线:\n",i);
pointer = entity;
do{ printf("第%d条直线:\n",i); printf("X1=%f\tY1=%f\tZ1=%f\n",pointer->data.line.x1, pointer->data.line.y1,pointer->data.line.z1); printf("X2=%f\tY2=%f\tZ2=%f\n",pointer->data.line.x2, pointer->data.line.y2,pointer->data.line.z2);
i++; }while(pointer !=NULL); } }
由于本人不是计算机专业的,水平有限,请多指点。
2. 李建明,陆润明,李学志编著, AutoCAD R12应用与开发教程 学苑出版社 1994 3. 谭浩强主编 C程序设计第二版 清华大学出版社 1999; |
|