你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
基于OpenDWG开发AutoCAD Proxy对象图元分解程序
 

  :本文主要介绍如何利用OpenDWG工具开发AutoCAD Proxy对象的图元分解程序。在分析AutoCAD Proxy对象特征基础上,对其带来的问题进行讨论,然后介绍利用OpenDWG工具开发图元分解程序的原理,并对其中关键的源程序进行详细解释。

关键词:ObjectARXProxyOpenDWG,图元分解

 

一、AutoCAD Proxy对象简介

AutoCAD平台上的二次开发工具包——面向对象的实时扩展编程语言(ObjectARX),以其良好的开放性迅速被广大的机械工程师和软件开发商接受。许多开发者利用ObjectARX创建了很多图形和非图形对象,这些对象能够插入到DWG文件中,通常称之为自定义对象。

使用自定义对象对于开发者来说非常方便,利用ObjectARX提供的派生机制,开发者能够从AcDbObjectAcDbEntity等对象基类派生自己的图形和非图形对象,按照最终用户的要求自由地控制对象的数据结构和显示方式,并提供方便的编辑手段。

ObjectARX提供了完善的开发接口用于支持对象派生,在AutoCAD二次开发领域,这种做法正越来越普遍。鉴于本文是讨论基于OpenDWG的应用开发技术,关于ObjectARX二次开发的的知识可以参考有关的书籍。

为了在DWG文件中显示和使用这些对象,创建这些对象的ARX应用程序必须可用(即已经加载到AutoCAD中)。否则,AutoCAD将自动用临时的Proxy对象代替这些自定义对象。当ARX应用程序再次变得可用时,AutoCAD将用自定义对象代替Proxy对象。

二、AutoCAD Proxy对象带来的问题

如上所述,自定义对象给开发者和用户带来方便的同时,由于其对ARX应用程序存在严重的依赖性,这将带来一些问题。

在下列情况下,用户将遇到AutoCAD临时用Proxy对象代替自定义对象的现象:

1)       打开一张包含自定义对象的图纸,但此时创建这些自定义对象的ARX应用程序没有安装在系统中。

2)       在当前图纸中,创建自定义对象的ARX应用程序被卸载。

第一种情况非常普遍,比如,当用户A有一张包含自定义对象的图纸传给用户B时,由于某些原因,没有或不能把创建自定义对象的ARX应用程序同时传给用户B。当用户B打开这张图纸时,AutoCAD将临时用Proxy对象代替这些自定义对象。

    每次当用户B打开图纸时,在AutoCAD 2000英文版平台上,系统提示如图1所示的对话框:

1

对于这个问题,可以通过设置AutoCAD的配置选项对该对话框进行屏蔽。如图2所示,关闭“Show Proxy Information dialog”检查框,下次打开包含Proxy图元的图纸将不弹出图1对话框。


2

然而,更严重的问题是,由于ARX应用程序不可用,用户B将不能对图纸中的Proxy图元进行任何操作,包括更改属性、移动、缩放、旋转、删除等,这就限制了对图纸进行进一步的编辑修改。

本文后面的内容将叙述基于OpenDWG开发程序来解决这个问题。

三、基于OpenDWG的解决方案

国际OpenDWG联盟(www.opendwg.org)组织提供的OpenDWG开发工具包(以下简称ODT)能够处理AutoCAD2.5到最新的2000/2002版本的dwg/dxf图纸。利用ODT提供的针对AutoCAD自定义对象的支持,可以开发程序来处理Proxy图元不能编辑的问题。

针对自定义图形对象(非图形对象可同样处理),解决问题的思路是,AutoCAD Proxy对象显示在图纸上的内容无非是圆、圆弧、直线、文字等基本图素,若能够对Proxy图元进行遍历,得到这些圆、圆弧、直线、文字等子图元数据(包括颜色、线型、线宽等显示属性),我们就可以在DWG文件中(按照图元数据及显示属性)重新创建这些子图元,然后删除原有的Proxy对象,最后保存DWG文件。

这样,在AutoCAD中重新打开该图纸,由于Proxy的干扰已被去除,用户可以进行自由地编辑修改。下面所述的程序即根据上述思路开发出来的。

关于Proxy对象,ODT提供了完善的API对其进行支持,这里介绍几个主要的函数:

1)       AD_IS_A_PROXYENT():判断是否是Proxy图元

2)       adStartBlobRead():获取数据链表

3)       adReadGrblobData():读取Proxy子图元数据

4)       adEndBlobRead():释放数据链表

具体的用法参见下面的源程序。本文列出的全部源程序在Windows 2000 Professional平台上使用Visual C++ 6.0编译通过,OpenDWG开发包的版本是2.0,可以支持AutoCAD 2000/2002

关于OpenDWG一般的开发步骤,请参见较早期发表的文章《利用OpenDWG读取AutoCAD文件信息》,更详细的信息参见www.opendwg.org提供的有关文档。

下面对基于OpenDWG开发AutoCAD Proxy对象图元分解程序开发中的主要步骤和源程序进行详细解释。

四、主要步骤和源程序

4.1 打开DWG文件,访问模型空间,获取图元链表。

AD_DB_HANDLE ad_db_handle;//文件句柄

ad_db_handle = adLoadFile((char *)strFileName, AD_PRELOAD_ALL, 1);

AD_OBJHANDLE ad_model_space;//模型空间

adFindBlockheaderByName(ad_db_handle, "*MODEL_SPACE", ad_model_space);

AD_VMADDR ad_ent_list;//图元链表

ad_ent_list = adEntityList(ad_db_handle, ad_model_space);

4.2 遍历DWG文件搜索Proxy对象,记录在句柄数组中。

EntHandleArray EntArray;

    adStartEntityGet(ad_ent_list);

    while (adGetEntity(ad_ent_list, ad_ent_hdr, ad_ent))

    {

        if (AD_IS_A_PROXYENT(ad_ent_hdr->enttype) &&

            ad_ent_hdr->enttype != adLwplineEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adOle2frameEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adImageEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adArcAlignedTextEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adWipeoutEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adRtextEnttype(ad_db_handle) &&

            ad_ent_hdr->enttype != adHatchEnttype(ad_db_handle) &&

            ad_ent->proxyent.grblob != AD_VMNULL)

        {//记录Proxy图元数组

            RecordEnt(EntArray, ad_ent_hdr->enthandle);

        }

    }

1)       数组EntHandleArray的定义如下所示:

class EntHandle

{

public:

        EntHandle() { adHanclear(objhandle); }

        EntHandle(AD_OBJHANDLE handle) { adHancpy(objhandle, handle); }

        virtual ~EntHandle() {}

    AD_OBJHANDLE objhandle;

};

typedef CArray<EntHandle*,EntHandle*> EntHandleArray;

2)       记录图元数组的函数定义如下所示:

void RecordEnt(EntHandleArray& EntArray, AD_OBJHANDLE handle)

{

        EntHandle *ptr = new EntHandle(handle);

        EntArray.Add(ptr);

}

3)       释放图元数组的函数定义如下所示:

void FreeEnts(EntHandleArray& EntArray)

{

        for (int i=0;i<EntArray.GetSize();i++)

        {

            delete EntArray[i];

        }

        EntArray.RemoveAll();

}

4.3 转换Proxy图元,处理之后删除。

for (int i=0;i<EntArray.GetSize();i++)

    {

        adSeekEntity(ad_db_handle, ad_ent_list, EntArray[i]->objhandle, ad_ent_hdr, ad_ent);

        AD_OBJHANDLE enthandle;

        adHancpy(enthandle, ad_ent_hdr->enthandle);

        //转换Proxy图元

        CheckProxyEnt(ad_ent_hdr, ad_ent);

        //删除

        adDeleteEntity(ad_db_handle, ad_ent_list, enthandle, AD_DELETE_BLOBS);

    }

    //释放图元数组

    FreeEnts();

1)     转换Proxy图元的函数定义如下所示:

BOOL CheckProxyEnt(PAD_ENT_HDR adEntHdr, PAD_ENT adEnt)

{

    adHancpy(cur_layer_handle, adEntHdr->entlayerobjhandle);//图层

    adHancpy(cur_ltype_handle, adEntHdr->entltypeobjhandle);//线型

    cur_ent_color = adEntHdr->entcolor;//颜色

    //获取Proxy子图元数据链表

    PAD_BLOB_CTRL bcptr = adStartBlobRead(adEnt->proxyent.grblob);

    //遍历

adStartGrblobDataRead(bcptr);

    AD_GR_DATA grdata;

    while (adReadGrblobData(bcptr, &grdata))

    {

        if (grdata.grtype == AD_GRENT_CIRCLE)

        {//处理圆

            CheckCircle(&grdata.grbody.circle);

        }

        else if (grdata.grtype == AD_GRENT_CIRCULARARC)

        {//处理圆弧

            CheckCircularArc(&grdata.grbody.circulararc);

        }

        else if (grdata.grtype == AD_GRENT_POLYLINE)

        {//处理直线

            CheckPolyline(&grdata.grbody.pline, bcptr);

        }

        else if (grdata.grtype == AD_GRENT_TEXT)

        {//处理文字

            CheckText(&grdata.grbody.text);

        }

    }

    adEndBlobRead(bcptr);

    return TRUE;

}

2)         处理圆的函数定义如下所示:

BOOL CheckCircle(AD_GR_CIRCLE *pGrObj)

{

    ad_ent_hdr->enttype = AD_ENT_CIRCLE;

    adSetEntityDefaults(ad_db_handle, ad_ent_hdr, ad_ent);

    adGenerateObjhandle(ad_db_handle, ad_ent_hdr->enthandle);

    ad_ent->circle.pt0[0] = pGrObj->pt0[0];//圆心

    ad_ent->circle.pt0[1] = pGrObj->pt0[1];

    ad_ent->circle.radius = pGrObj->radius;//半径

    adHancpy(ad_ent_hdr->entlayerobjhandle, cur_layer_handle);

    adHancpy(ad_ent_hdr->entltypeobjhandle, cur_ltype_handle);

    ad_ent_hdr->entcolor = cur_ent_color;

    //增加图元

    if (!adAddEntityToList(ad_db_handle, ad_ent_list, ad_ent_hdr, ad_ent))

        return FALSE;

    return TRUE;

}

3)         处理圆弧的函数定义如下所示:

BOOL CheckCircularArc(AD_GR_CIRCARC *pGrObj)

{

    ad_ent_hdr->enttype = AD_ENT_ARC;

    adSetEntityDefaults(ad_db_handle, ad_ent_hdr, ad_ent);

    adGenerateObjhandle(ad_db_handle, ad_ent_hdr->enthandle);

    ad_ent->arc.pt0[0] = pGrObj->pt0[0];//圆心

    ad_ent->arc.pt0[1] = pGrObj->pt0[1];

    ad_ent->arc.radius = pGrObj->radius;//半径

    ad_ent->arc.stang = lGetAngle(pGrObj->startvector[0], pGrObj->startvector[1]);//起始角

    ad_ent->arc.endang = ad_ent->arc.stang + pGrObj->sweepangle;//终止角

    adHancpy(ad_ent_hdr->entlayerobjhandle, cur_layer_handle);

    adHancpy(ad_ent_hdr->entltypeobjhandle, cur_ltype_handle);

    ad_ent_hdr->entcolor = cur_ent_color;

    //增加图元

if (!adAddEntityToList(ad_db_handle, ad_ent_list, ad_ent_hdr, ad_ent))

        return FALSE;

    return TRUE;

}

4)         处理直线的函数定义如下所示:

BOOL CheckPolyline(AD_GR_PLINE *pGrObj, PAD_BLOB_CTRL bcptr)

{

    CArray<double,double> xArray, yArray;

    int Count = pGrObj->numpts;

    for (int i=0;i<Count;i++)

    {

        double pt[3];

        adReadGrblobVertexPt(bcptr, pt);

        xArray.Add(pt[0]);//端点

        yArray.Add(pt[1]);

    }

    for (i=0;i<xArray.GetSize() - 1;i++)

    {

        ad_ent_hdr->enttype = AD_ENT_LINE;

        adSetEntityDefaults(ad_db_handle, ad_ent_hdr, ad_ent);

        adGenerateObjhandle(ad_db_handle, ad_ent_hdr->enthandle);

        ad_ent->line.pt0[0] = xArray[i];//起点

        ad_ent->line.pt0[1] = yArray[i];

        ad_ent->line.pt1[0] = xArray[i + 1];//终点

        ad_ent->line.pt1[1] = yArray[i + 1];

        adHancpy(ad_ent_hdr->entlayerobjhandle, cur_layer_handle);

        adHancpy(ad_ent_hdr->entltypeobjhandle, cur_ltype_handle);

        ad_ent_hdr->entcolor = cur_ent_color;

        //增加图元

if (!adAddEntityToList(ad_db_handle, ad_ent_list, ad_ent_hdr, ad_ent))

            return FALSE;

    }

    return TRUE;

}

5)         处理文字的函数定义如下所示:

BOOL CheckText(AD_GR_TEXT *pGrObj)

{

    ad_ent_hdr->enttype = AD_ENT_TEXT;

    adSetEntityDefaults(ad_db_handle, ad_ent_hdr, ad_ent);

    adGenerateObjhandle(ad_db_handle, ad_ent_hdr->enthandle);

ad_ent->text.pt0[0] = pGrObj->pt0[0];//基点

    ad_ent->text.pt0[1] = pGrObj->pt0[1];

    ad_ent->text.tdata.height = pGrObj->height;//字高

    ad_ent->text.tdata.widthfactor = pGrObj->widthfactor;//宽度因子

    ad_ent->text.tdata.oblique = pGrObj->oblique;//倾斜角

    strcpy(ad_ent->text.textstr, pGrObj->textstr);//文字串

    adHancpy(ad_ent_hdr->entlayerobjhandle, cur_layer_handle);

    adHancpy(ad_ent_hdr->entltypeobjhandle, cur_ltype_handle);

    ad_ent_hdr->entcolor = cur_ent_color;

    //增加图元

    if (!adAddEntityToList(ad_db_handle, ad_ent_list, ad_ent_hdr, ad_ent))

        return FALSE;

    return TRUE;

}

应该注意到,上述对Proxy对象的处理是不完整的,读者可以参考上述的源程序,开发AD_GRENT_CIRCLE3PTAD_GRENT_CIRCULARARC3PTAD_GRENT_POLYGONAD_GRENT_MESHAD_GRENT_SHELLAD_GRENT_TEXT2AD_GRENT_XLINEAD_GRENT_RAY等类型图元的处理程序,同时考虑图元的显示属性,包括颜色(AD_GRENT_SUBENT_COLOR)、图层(AD_GRENT_SUBENT_LAYER)、线型(AD_GRENT_SUBENT_LINETYPE)等。

4.4 保存DWG文件

//获取文件类型(DWG/DXF)

int nSaveType = GetFileType();

//获取文件版本

int nSaveVer = GetFileVer();

//保存DWG文件

adSaveFile(ad_db_handle, (LPSTR &)strFileName, nSaveType, nSaveVer, 0, 0, 0, 0);

五、运行实例

基于上述思想,笔者基于OpenDWG开发出用于处理AutoCAD Proxy图元的图纸文件转换程序ConvertDwgIncProxyEnt.exe,并在实践中应用良好。

运行界面如图3所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

3

 

其中:

1)       点取“选择图纸”可以一次选择多张图纸进入“文件列表”。

2)       点取“选择目录”可以选择指定目录中的全部DWG文件进入“文件列表”。

3)       点取“清空列表”可以清除“文件列表”中的全部文件。

4)       点取“开始转换”,系统将处理图纸中的Proxy图元,并在“转换结果”中显示转换进度和转换结果。

5)       任务完成,点取“退出”按钮。

六、进一步的工作

由于OpenDWG不是AutoDesk公司提供的开发工具,读者可能会有这样的疑虑,用OpenDWG分解Proxy图元对象之后,若直接对DWG文件存盘,可能会损坏其中的图形数据,导致随后不能被AutoCAD打开进行查看和编辑。

虽然这种猜测没有在实践中得到验证,但保持谨慎的心理是有必要的。这里提供一种思路,仅用OpenDWG遍历DWG文件获取其中Proxy子图元的信息,用ObjectARX进行后续处理。由于后者是AutoDesk公司提供的开发包,自然不会破坏DWG文件。具体步骤是,从DWG文件中获取Proxy对象分解得来的子图元信息之后,不再用OpenDWG函数进行增加图元、删除Proxy对象、保存DWG文件等操作,而用ObjectARX提供的开放接口处理增加图元、删除Proxy对象、保存DWG文件等操作。

然而,结合ObjectARX开发的应用程序不再具有独立性,程序依赖AutoCAD运行。这是其唯一的缺点。

建议有兴趣的读者继续作进一步的开发工作,以彻底消除OpenDWG破坏DWG文件图形数据的可能性。

 

 

  推荐精品文章

·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 
·2023年7月目录
·2023年6月目录 
·2023年5月目录
·2023年4月目录 
·2023年3月目录 
·2023年2月目录 
·2023年1月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089