摘 要
AutoCAD的DWG格式文件是其它图形软件的主要数据源,常常需要将其转换成其它格式。本文在讨论了DWG文件访问方法的基础上,重点介绍了基于ObjectARX的DWG文件的访问步骤与读取方法,并给出了关
键代码。 关键词 ObjectARX;DWG;文件访问
Autodesk 公司出品的 AutoCAD是目前市场上用户群体最大的一个图形处理软件包,其图形数据文件往往是其它图形软件(含GIS软件)的主要图形数据源。因此,如何可靠读取或操作 DWG
格式的图形数据并存储成其它格式的文件,便成为应用系统建立时不可忽视的问题,同时,这也是一直困扰软件技术人员的难题。
1 DWG文件的访问方法 DWG格式图形文件的访问方法主要有三种。
1.1
直接读写二进制加密格式的 DWG 文件
AutoCAD系列产品版本不断升级,图形数据结构也随之变化,自行编写读写代码,必须分析各版本图形文件结构,针对不同版本编写读写代码。这种工作量很大,短期内无法实现。购买第三方应用程序接口软件(如 OpenDWG 和 DrDWG 等),也可读写二进制加密格式的 DWG 文件,但需要较大的资金投入。
1.2 通过 AutoCAD 软件的 OLE/ActiveX 自动化接口实现读写 程序员只需熟悉 VC 编程、了解
DWG 文件基本知识,很快就能开展工作。这种方法开发周期短,开发费用低,对程序员的知识储备要求低,是经济实用的开发手段。但缺点是运行速度慢,运行时必须安装有 AutoCAD的相应产品。
1.3在AutoCAD环境下编程读写
通过 Autodesk 公司提供的ObjectARX/ADS、VBA或Visual Lisp在 AutoCAD 内部操作 DWG文件,这种方法极为可靠,但是有开发难度大、对初学者很难上手、程序调试复杂等特点。在高版本的开发中,由于地址共享及代码编写不当,还可能造成AutoCAD系统崩溃,但也是目前使用人数最多的一种方法。 ObjectARX应用程序是一个动态链接库(DLL),它共享AutoCAD的地址空间并直接调用AutoCAD的函数。可以向ObjectARX程序环境添加新类,并将其输出以供其他程序使用,也可以通过向既有的AutoCAD类添加函数来扩充ObjectARX协议。
2 基于ObjectARX的DWG文件读取方法
2.1 AutoCAD数据库概述
AutoCAD数据库是按一定结构组织的各有相关数据的集合。它可以用来存储组成AutoCAD图的对象和实体。Dwg图是一个储存在数据库中的对象集合。基本的数据库对象是实体,符号表和词典。图1中列出了组成AutoCAD数据库的主要部件。
图1 组成AutoCAD数据库的主要部件
在AutoCAD中创建的对象被添加到数据库对应的容器对象中,实体被添加到块表的记录中,符号表记录被添加到相应的符号表中,所有其他的对象被添加到命名对象词典中,或添加到其他对象拥有的对象(拥有其他对象的对象最终属于命名对象词典)中,或添加到扩充词典中。
实体是在AutoCAD图内部表示图的一种特殊数据库对象,线、圆、弧、文本、实心体、区域、复合线和椭圆都是实体,用户可以在屏幕上看见实体并能对其进行操作。基本实体在有的资料中也被称为“图元”。在AutoCAD环境中,使用一个长整数来表示实体,这就是实体的名称。实体名是“临时性的”,它们只在当前图形编辑器中有效。当用户关闭当前图形打开另一幅图形后,实体名就会失效。例如,在某个编辑会话期间,一个实体的实体名可能为“60004722”,而在另一个会话期间,则可能为“87635072”。
在一个AutoCAD会话中,可以加载多个数据库。在会话中的每个对象都有一个句柄和对象ID。在特点的数据库范围内句柄唯一地识别对象,而在一次加载的所有数据库内对象ID唯一地识别对象。对象ID只在一个编辑会话内存在,但句柄保存在图中。
2.2 访问DWG文件的步骤与方法
2.2.1 读取AutoCAD数据库
ObjectARX提供了大量与AutoCAD编辑器通信的类和成员函数,可以通过调用下面的全局函数来获得当前数据库:
acdbHostApplicationServices()->workingDatabase()AutoCAD图是一个储存在数据库中的对象的集合。基本的数据库对象是实体、符号表和词典。符号表是用于存储数据库对象的容器。其中块表(AcDb
BlockTable)也是一个符号表,包含块表记录。所有AutoCAD实体都属于块表记录。所有打开图形数据库后就要打开该数据库的块表记录来获得实体信息。AcDbBlockTable
*pBlockTable;acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlockTable,AcDb::kForRead);//打开图形数据库的块表AcDbBlockTableRecord
*pBlockTableRecord;pBlockTable->getAt(ACDB_MODEL_SPACE,pBlockTableRecord,AcDb::kForRead);//获得块表的记录
2.2.2 获得数据库中实体
可以通过三种不同的方法找到一个AcDbEntity实体:从其句柄;从其对象ID;从C++实例指针。
当未运行AutoCAD时,图存储在文件系统中,对象包含在DWG文件中,由其句柄识别。图打开后,图信息可通过AcDbDatabase对象访问,每个对象在数据库中都有一个对象ID,它从对象一建立就一直存在
于当前编辑会话中,直到对象所在的AcDbDatabase被删除为止。要对一个实体进行操作访问之前,ObjectARX应用程序必须首先调用能返回实体名的库函数,以得到该实体的名称。打开函数将对象ID作为
一个变元并返回一个指向AcDbObject对象的指针,该指针在关闭对象以前一直有效。 可以用acdbOpenAcDbEntity()函数打开实体,其函数原型为:Acad::ErrorStatus
acdbOpenAcDbEntity(AcDbEntity*& pEnt,AcDbObjectId id,AcDb::OpenMode mode,bool openErasedEntity = false);也可以用下面的函数将一个句柄映射到实体ID:Acad::ErrorStatus
getAcDbObjectId(AcDbObjectId& retId,bool createIfNotFound,const AcDbHandle& objHandle,Adesk::UInt32 xRefId = 0);还可以用下面这个函数打开对象,然后获取其句柄:
AcDbObject *pObject; AcDbHandle handle; pObject->getAcDbHandle(handle);
与实体名一样,在图形中句柄也是唯一的。与实体名不同的是,一个实体的句柄永久不变。例如,一个实体的名称可能是“60004722”,而其句柄可能是“5a2”。不管在哪个编辑会话期间,该实体的句柄总
是“5a2”。 上述方法都可以获得DWG文件中的一个具体的实体,然后就能方便的获得其信息。
2.2.3 读取实体信息
打开实体后,ObjectARX提供了一系列函数用来设置和查询实体信息,如颜色、线型、线型比例、层、线宽等。可以采用以下几种函数来分别读取这些信息。 1) 颜色 AcCmColor
AcDbEntity::color() const;
这里得到的并不是AutoCAD的颜色索引号,必须再用AcCmColor::getColorIndex()函数从AcCmColor类的对象中获取颜色的索引号。如果直接用函数AcDbEntity::colorIndex()得到的索引号包括0(随块)
、256(随层)、257(无色)这些特殊的索引号,不能满足需要。必须先读取实体所在图层的颜色,从AcCmColor
AcDbLayerTableRecord::color()获取该图层颜色,在通过AcCmColor类的对象中获取颜色的准确的索引号,可以利用这些索引号在通过查RGB颜色表获得通用的RGB颜色,以满足其他文件格式的需要。
2) 线型 char * AcDbEntity::linetype() const;
如果实体的线型设置为ByLayer的时候,该函数就返回“Bylayer”字符串,必须找到对应的层,然后通过打开线型表获得对应的具体线型。
3) 线型比例double AcDbEntity::linetypeScale()
const; 4) 层char * AcDbEntity::layer() const;以上信息是所有实体的公共信息,几乎每个实体都能用这些函数取得相关信息。5)
其他几何信息不同的实体,其几何信息不同,但读取方法类似。下面的例子将读取一个基本实体圆弧(AcDbArc)的基本信息。void arc_data(AcDbArc *eArc)//输出圆弧数据{int
color=eArc->colorIndex();//读取圆弧的索引颜色double lineThick=eArc-> thickness ();//读取圆弧的厚度int lineWidth=eArc->lineWeight();//读取圆弧线宽char
*linetype=eArc->linetype();//读取圆弧的线型AcGePoint3d center;center=eArc->center();//读取圆弧的圆心char *layerName= eArc->layer();//读取圆弧所在图层double
dblRadius=eArc->radius();//读取圆弧半径double dblStart= eArc->startAngle();//读取圆弧起始角度double dblEnd= eArc->endAngle();//读取圆弧结束角度}
在AutoCAD中还存在一些复杂的实体,这些复杂的实体则包含其他对象,这些对象保存着实体的几何图形信息。可以用explode()函数把一些实体分解成一系列简单的元素,如长方体能被先分解成面,再
分解成直线,多义线则能被分解成直线段和圆弧段,多行文字能被分解成单行文字,等等。图2是在AutoCAD中生成的AcDbBlockReference块引用。可以看到该AcDbBlockReference块引用由两条圆弧AcDbA
rc、两条直线AcDbLine、三个点实体AcDbPoint以及文字AcDbText组成,是AutoCAD中比较有代表性的实体。
图2 块参照在AutoCAD中的图形
块参照往往由几个基本实体组成,无法像简单实体一样直接用插入坐标、图层等来确定它的形状特征。所以ARX提供了explode
()函数分解复杂实体。对块引用进行分解时,AutoCAD复制块引用中所有的实体并将它们分解成单独的元素添加到图形数据库中去,它同AutoCAD中执行EXPLODE命令不同。关键代码如下所示。acdbOpenOb
ject(eBlockReference,entityId,AcDb:: kForRead);//以只读方式打开块参照AcDbVoidPtrArray entitySet;eBlockReference->explode(entitySet);
上述语句把块参照打散后,返回的一组实体保存在AcDbVoidPtrArray类型的数组中。通过下面的循环即可读取所有实体的信息。for(int i=0;i *)entitySet.at(i);if(strcmp("AcDbLine",(ent->isA()->name()))==0) { AcDbLine *eline; eline=(AcDbLine *)ent; line_data(eline); //读取线实体信息}if(strcmp("AcDbText",(ent->isA()->name()))==0) { AcDbText *eText; eText=(AcDbText *)ent; text_data(eText); //读取文字实体信息}if(strcmp("AcDbArc",(ent->isA()->name()))==0) { AcDbArc *eArc; eArc=(AcDbArc *)ent; arc_data(eArc); //读取圆弧实体信息}…//其他组成块引用的基本实体的信息读取} 2.2.4 关闭实体 必须注意,无论何时打开数据库对象,应尽可能早的关闭。可以使用AcDbEntity::close()函数关闭数据库实体。 3 总结与展望 利用ObjectARX读取DWG文件的编程是比较简单易用的,而且速度比其他方法较快。AutoCAD是目前在Windows环境下应用最广泛、使用人数最多的CAD支撑软件,DWG格式也是目前保存基础地理矢量数据最 基本的格式。随着GIS的迅速发展,GIS软件也在迅速发展增多,如ESRI公司的ArcGIS,它生成的shp格式已经得到广泛的应用,但是基础的地理数据仍然是DWG格式,这就需要进行格式转换。于是研究DWG 文件的读取方法,再通过把DWG转为TXT通用文本格式,可以说是一种DWG转成其他格式的的一种基础,也是一种万能方法。首先,可以通过程序选择需要的数据输出,这大大方便了数据的处理,之后如果 熟悉其他文件格式的结构,就能通过读取这个TXT文件中的数据来转换生成其他数据格式,而不需要再去读取和研究DWG文件的格式。