在程序里的一个对话框里显示一个矢量文件,并可进行简单的更改请问有什么建议吗
解决方案 »
- 急需王育坚的《VC++面向对象编程教程》的源码!
- 高分求个系统
- 怎么把一本地文件夹里文件的文件名、创建时间、大小全都读到一个list中?
- 一个简单的奇怪问题,求各位大侠帮忙
- 十万火急?
- 有谁用过SetDrawTextFlags?我想用它设置工具条按钮的显示位置(显示在按钮下面),不知道怎么做啊?
- 如何控制程序运行中暂停与继续?
- CArray类
- 那位知道控制打印机的win32函数,1、使其打印完毕不换页(卷纸) 2、以及换行的函数!!!
- 如何对upx压缩过的DLL文件脱壳(procdump只能脱exe文件)
- 线程:我想在一个基于对话框的程序中实现以下功能,一个线程放声音,一个放AVI,启用了用户界面线程,可是报错。
- 硬盘阵列如何获得硬盘序列号
告诉我一声
我也正准备做这个!!
[email protected]我们使用 Visual C++ 6.0 来写一个读取DXF文件的小程序。 在实际应用中,模型中实体的数目以及实体中点和面的数目都是不定的,为
了有效地利用内存,我们选择MFC类库中的聚合类CobArray类所创建的对象
vertex, sequence来存储和管理实体的点坐标和点序。 CObArray类是一个用来存放数组类的聚合类,它能根据要存进来的数组(或
结构)多少自动进行自身大小的高速,而且这个类本身具有的成员函数使得我们
对它的对象的操作更加方便、快捷,用它编的程序也易于读懂。
三维实体模型的模型信息中的一部分信息可以在标题段中读出,通过读取变
量名为$UCSORG的三个变量,可以得到三维实体在世界坐标系中自身所定义的用
户坐标系原点的三维坐标。通过读取$EXTMAX,$EXTMIN可以获知三维实体在世
界坐标系中的范围,而其它部分的信息只有读完了全部DXF文件后才可以通过计算
确定。对于三维实体模型的全部点坐标、点序,可以在实体段中按照前面介绍的
DXF文件基本结构读出。现在我们开始写这个程序。 先建立一个头文件HEAD.H定义如下的结构:VERTEX, SEQUENCE和类CVertex, Csequence。 typedef struct { float x,y,z; }VERTEX; 结构VERTEX用来存储点的坐标 typedef struct { int a,b,c; }SEQUENCE; 结构SEQUENCE用来存储实体的面的组成 typedef struct { char obName[20]; 定义结构myVertex来存储实体的名字,点的坐标以及面的组成, CObArray Vertex; 其中,点的坐标和面的组成是由聚合类CObArray定义的对象来 CObArray Sequence; 在存储的,我们可以把VERTEX结构和SEQUENCE结构加入到 }myVertex; 这两个对象中保存 class CVertex : public CObject { 因为CObArray类的对象中只能加入由CObject派生的对象,所以 protected: 我们还需要建立一个由CObject类派生的CVertex类。在CVertex类 CVertex(); 中有一个VERTEX结构的变量:m_vertex,信息实际上是存储在这 DECLARE_DYNCREATE(CVertex) 个变量中的。 virtual ~CVertex(); // Attributes public: 我们还需要建立一个由CObject类派生的CVertex类。在CVertex类 CVertex(VERTEX& ver); 中有一个VERTEX结构的变量:m_vertex,信息实际
上是存储在这个变量中的,函数CVertex(VERTEX& ver)把VERTEX结构的变量 VERTEX m_vertex; 存入CObArray对象中。 }; class CSequence : public CObject { 这也是一个由CObject类派生的类,作用和刚才CVertex类一样, protected: 只不过Csequence类是用来存储实体中面的组成(点序)的。 CSequence(); DECLARE_DYNCREATE(CSequence) virtual ~CSequence(); public: CSequence(SEQUENCE& sequ); SEQUENCE m_sequence; }; 声明好结构与类后,我们还需要建立一个.CPP文件,来定义几个函数。 IMPLEMENT_DYNCREATE(CVertex,CObject) CVertex::CVertex() { } CVertex::~CVertex() 构造函数和销毁函数都是空的 { } CVertex::CVertex(VERTEX& ver) { 这个函数的作用是:把一个VERTEX结构的数据存入变量m_vertex中 m_vertex = ver; 它是这个类中最重要的一环。 } IMPLEMENT_DYNCREATE(CSequence,CObject) CSequence::CSequence() { } Csequence类的定义与CVertex类的定义差不多,只是其中的参数 m_sequence的类型和CVertex类中的参数my_vertex的类型不一样 CSequence::~CSequence() { } CSequence::CSequence(SEQUENCE& sequ) { m_sequence=sequ; }
型中实体的多少来给指针分配合适的内存,使之成为结构数组。 定义一个函数,用于确定模型中有多少个实体,函数的返回值就是实体的个数。 int CJupiterView::getObjectNumber() { char str1[10],str2[10]; char name[]="theFirst"; int num; num=0; FILE* fp; fp=fopen("data.dxf","r"); 打开DXF文件,data.dxf while(! feof(fp) && ! ferror(fp)) 这个函数是根据实体的名字来判断实体的个数的 { 所以函数只读取实体的名字,一旦出现新的实体名字, fscanf(fp,"%s",str1); 实体数就加一。 if(strcmp(str1,"VERTEX")==0) { fscanf(fp,"%s",str2); 打开DXF文件,data.dxf fscanf(fp,"%s",str2) ;这个函数是根据实体的名字来判断实体的个数的 if(strcmp(name,str2) != 0) 所以函数只读取实体的名字,一旦出现新的实体名字, {实体数就加一。 strcpy(name,str2); num++; } } } fclose(fp); return num; } 以下是读取实体点的坐标以及点序的程序代码,在这个程序中,读取了模型
中点的坐标的最大值与最小值、实体的名字、点的坐标,以及点序。 void CJupiterView::OnFileInput() { // TODO: Add your command handler code here FILE* fp,*fp2; int i,k,j; float tempX,tempY,tempZ; float xMin,yMin,zMin,xMax,yMax,zMax,Max; int lab; char str1[20],str2[20],str[20],HT; char myName[20]; int myNumber; VERTEX tempVertex; SEQUENCE tempSequence; typedef struct { float x,y,z,max; }MAX; MAX max; HT=9; objectNumber=getObjectNumber(); myData=new myVertex[objectNumber]; fp=fopen(FileName,"r"); i=0; j=0; k=0; myNumber=-1; strcpy(myName,"ObjectName"); while(! feof(fp) && ! ferror(fp)) { fscanf(fp,"%s",str); if(strcmp(str,"$EXTMIN")==0) { fscanf(fp,"%s",str1); fscanf(fp,"%f",&xMin); fscanf(fp,"%s",str1); fscanf(fp,"%f",&yMin); fscanf(fp,"%s",str1); fscanf(fp,"%f",&zMin); } if(strcmp(str,"$EXTMAX")==0) { fscanf(fp,"%s",str1); fscanf(fp,"%f",&xMax); fscanf(fp,"%s",str1); fscanf(fp,"%f",&yMax); fscanf(fp,"%s",str1); fscanf(fp,"%f",&zMax); max.x=max(abs(xMax),abs(xMin)); max.y=max(abs(yMax),abs(yMin)); max.z=max(abs(zMax),abs(zMin)); max.max=max(max.x,max.y); max.max=max(max.max,max.z); } if(strcmp(str,"VERTEX") ==0) { fscanf(fp,"%s",str1); fscanf(fp,"%s",str1); if(strcmp(myName,str1) != 0) { myNumber++; strcpy(myName,str1); strcpy((myData+myNumber)->obName,myName); } fscanf(fp,"%s",str2); fscanf(fp,"%f",&tempX); fscanf(fp,"%s",str2); fscanf(fp,"%f",&tempY); fscanf(fp,"%s",str2); fscanf(fp,"%f",&tempZ); fscanf(fp,"%d",&lab); fscanf(fp,"%d",&lab); if(lab == 192) { tempVertex.x=tempX / max.max; tempVertex.y=tempY / max.max; tempVertex.z=tempZ / max.max; (myData+myNumber)->Vertex.Add(new CVertex(tempVertex)); } if(lab == 128) { fscanf(fp,"%s",str1); fscanf(fp,"%f",&tempX); fscanf(fp,"%s",str1); fscanf(fp,"%f",&tempY); fscanf(fp,"%s",str1); fscanf(fp,"%f",&tempZ); tempSequence.a=abs(tempX); tempSequence.b=abs(tempY); tempSequence.c=abs(tempZ); (myData+myNumber)->Sequence.Add(new CSequence(tempSequence)); } } } fclose(fp); }
每个CAD系统都有自己的数据文件,数据文件分图形数据文件、几何模型文件和产品模型文件几种。数据文件的格式与每个CAD系统自己的内部数据模式密切相关,而每个CAD系统自己内部的数据模式一般是不公开的,也是各不相同的。由于用户使用的需要,就有数据交换文件概念的出现。
DXF为AutoCAD系统的图形数据文件,DXF虽然不是标准,但由于AutoCAD系统的普遍应用,使得DXF成为事实上的数据交换标准。DXF是具有专门格式的ASCII码文本文件,它易于被其它程序处理,主要用于实现高级语言编写的程序与AutoCAD系统的连接,或其它CAD系统与AutoCAD系统交换图形文件。
1 DXF文件结构
一个完整的DXF文件是由四个段和一个文件结尾组成的。其顺序如下:
(1)标题段,记录AutoCAD系统的所有标题变量的当前值或当前状态。这些标题变量记录了AutoCAD系统的当前工作环境。例如,AutoCAD版本号、插入基点、绘图界限、SNAP捕捉的当前状态、珊格间距、式样、当前图层名、当前线型和当前颜色等;
(2)表段,包含了四个表,每个表又包含可变数目的表项。按照这些表在文件中出现的顺序,它们依次为线型表、图层表、字样表和视图表;
(3)块段,记录定义每一块时的块名、当前图层名、块的种类、块的插入基点及组成该块的所有成员。块的种类分为图形块、带有属性的块和无名块三种。无名块包括用HATCH命令生成的剖面线和用DIM命令完成的尺寸标注;
(4)元素段,记录了每个几何元素的名称、所在图层的名称、线型名、颜色号、基面高度、厚度以及有关几何数据;
(5)文件结束,标识文件结束。
DXF文件每个段由若干个组构成,每个组在DXF文件中占有两行。组的第一行为组代码,它是一个非零的正整数,相当于数据类型代码,每个组代码的含义是由AutoCAD系统约定好的,以FORTRAN “I3”格式(即向右对齐并且用三字符字段填满空格的输出格式)输出。组的第二行为组值,相当于数据的值,采用的格式取决于组代码指定的组的类型。组代码和组值合起来表示一个数据的含义和它的值。组代码范围见下表。需要注意的是,在AutoCAD系统中组代码既用于指出如下表所示的组值的类型,又用来指出组的一般应用。组代码的具体含义取决于实际变量、表项或元素描述,但“固定”的组代码总具有相同的含义,如组代码“8”总表示图层名。
组代码范围 跟随值的类型
0-9 串
10-59 浮点
60-79 整数
210-239 浮点
999 注释
1000-1009 串
1010-1059 浮点
1060-1079 整数
表6.3 组代码范围
一个DXF文件的框架如下:
0 ......段开始
SECTION
2
HEADER ......该段为标题段
9
$ACADVER ......下面依次描述所有标题变量
1
AC1003
.
.
.
0
ENDSEC ......标题段结束
0
SECTION ......段开始
2
TABLES ......该段为表段
0
TABLE ......表开始
2
LTYPE ......该表为线型表
.
.
.
0
ENDTAB ......线型表结束
0
TABLE
2
LAYER ......图层表开始
.
.
.
0
ENDTAB ......图层表结束
0
TABLE
2
STYLE ......字样表开始
.
.
.
0
ENDTAB ......字样表开始
0
TABLE
2
VIEW ......视图表开始
.
.
.
0
ENDTAB ......视图表结束
0
ENDSEC ......表段结束
0
SECTION
2
BLOCKS ......块段开始
0
BLOCK ......块开始
.
.
.
ENDBLK ......块结束
.
.
.
0
ENDSEC ......块段结束
0
SECTION
2
ENTITIES ......元素表开始
0
xxxxxxx ......开始的元素
.
.
.
0
xxxxxxx ......又一个元素开始
.
.
.
0
ENDSEC ......元素段结束
0
EOF ......文件结束
2 DXF文件接口程序设计
DXF文件格式的设计充分考虑了接口程序的需要,它能够容易地跳过没有必要关心的信息,同时又能方便地提取所需要的信息。只要记住按何顺序处理各个组并跳过不关心的组即可。但编写一个输出DXF文件的程序是比较困难的,因为必须保持图形的一致性以使AutoCAD系统接受它。AutoCAD系统允许在一个DXF文件中省略许多项并且仍可获得一个合法的图形。如果不需要设置任何标题变量,那么整个HEADER段都可以省略。在TABLES段中的任何一个表,在不需要时也可以略去,并且事实上如果对它不作任何处理时,整个表段也可以去掉。如果在LTYPE表中定义了线型,则该表必须在LAYER表之前出现。如果图中没有使用块定义,则可以省略BLOCKS段。如果有,那么它必须出现在ENTITIES段之前。EOF必须出现在文件的末尾。
3 DXF文件格式存在的问题
(1)由于DXF文件制定的较早,存在很多的不足。不能完整地描述产品信息模型,产品的公差、材料等信息根本没有涉及。即使产品的几何模型,由于仅仅保留了原有系统数据结构中的几何和部分属性信息,大量的拓扑信息已不复存在,也是不完整的;
(2)DXF文件格式也不合理,文件过于冗长,使得文件的处理、存放、传递和交换不方便。另外,复杂的文件格式也使得编写一个读、写完整的DXF数据文件的程序接口是件不容易的工作。
随着CAD/CAM技术的发展和CAD/CAM系统应用的日益广泛,不同系统和系统不同子系统间的数据交换问题变得重要和迫切了,直接推动国家或国际上通用的数据交换文件标准的制定。