王光昇,周麗珠,劉允,周義軍
(天津市測繪院,天津 300381)
在過去的十年中,基于AutoCAD的地形圖成圖軟件在我們國內(nèi)制圖,設(shè)計(jì)領(lǐng)域一直占據(jù)著主導(dǎo)地位,這主要是因?yàn)锳utoCAD軟件在表現(xiàn)線劃圖形上方便易用以及Autodesk的品牌效應(yīng)。但從根本上來講,Autodesk的一系列產(chǎn)品中,并沒有多少功能是專門為我們測繪行業(yè)設(shè)計(jì)的,所以AutoCAD軟件自然也不是為測繪行業(yè)量身定做的。但是傳統(tǒng)的測繪成圖軟件,如廣州開思、南方開思軟件通過“堆砌”的方式將CAD原生要素,如文本、點(diǎn)、線等拼湊成地形要素的模樣,從圖面上來說,達(dá)到了表現(xiàn)地形的目的。這種成圖方式在從手工制圖向數(shù)字化成圖轉(zhuǎn)變過程中起到了不可替代的作用。然而在信息化測繪的今天,它的弊端就顯現(xiàn)出來了,數(shù)據(jù)冗余、圖形零散、編輯困難等??梢哉f,在這種成圖方式中,過于注重圖面表示,沒有突出“信息”的作用。我們必須調(diào)整數(shù)據(jù)采集及成圖方式以適應(yīng)信息化測繪要求。AutoCAD的ObjectARX開發(fā)工具為我們提供了自定義實(shí)體技術(shù),它可以幫助我們定制自己的地形圖要素,極大地優(yōu)化數(shù)據(jù)組織結(jié)構(gòu),提高數(shù)據(jù)應(yīng)用效率。由于自定義實(shí)體可以用程序控制要素的外觀顯示,所以,就可以根據(jù)不同的用戶信息動態(tài)表達(dá)出不同的外觀圖形,這更貼近信息化測繪的需要。
下面結(jié)合實(shí)例來分析一下定制自定義實(shí)體的基本思路。
我們自定義了一個符號對象MYSYMBOL,可以用來表現(xiàn)控制點(diǎn),如圖1所示。
圖1 自定義符號類
(1)通用性
設(shè)計(jì)的自定義對象,一般用來表示一大類要素,而不是某一個具體的要素。當(dāng)然對于某些特殊的要素要定義專門的自定義對象。如圖1所示的控制點(diǎn)對象,對象的名字為MYSYMBOL,之所以命名為Symbol,是因?yàn)槲覀兿胱屵@個對象能盡可能地表現(xiàn)所有點(diǎn)狀要素,如高程點(diǎn)、獨(dú)立符號等,如表1所示。
自定義對象的通用性 表1
表1中表現(xiàn)的符號并不是固定不變的,所用的符號樣式也是與編碼一一對應(yīng)的。這種對應(yīng)關(guān)系由外部配置文件進(jìn)行管理。
(2)編碼驅(qū)動
一般我們都是以編碼來標(biāo)識地物要素的,這一點(diǎn)沒有任何疑義,但是傳統(tǒng)成圖軟件是借用CAD內(nèi)部對象的thickness屬性來存儲編碼。為什么用它呢,因?yàn)樗旧鲜俏ㄒ豢梢栽趯傩悦姘逯行薷亩挥绊懚S平面圖形顯示的。但是thickness實(shí)際上是代表要素在三維空間中的厚度,如果我們把二維圖形切換到三維坐標(biāo)系下,就可以看到thickness帶來的影響了,所以用它存儲編碼顯然是不合適的。而對于塊符號對象根本是沒有thickness的,我們還需要通過符號名稱把編碼與地物聯(lián)系起來,邏輯關(guān)系復(fù)雜化了。
所以我們在自定義對象時,我們?yōu)槊總€自定義對象都添加一項(xiàng)字符串類型的編碼屬性(Code),就可以做到編碼與要素一一對應(yīng),而且字符串類型值不會產(chǎn)生類似Thickness的雙精度損失問題。
(3)屬性狀態(tài)控制
在考慮自定義對象的通用性的同時,還要符合用戶的實(shí)際應(yīng)用。表現(xiàn)高程點(diǎn)時,在屬性面板中就不應(yīng)該顯示“樣式”屬性,即對于不同的對象要顯示不同的屬性項(xiàng),如圖2所示。
圖2 自定義對象屬性狀態(tài)控制
(4)開放性
自定義的對象與一般的AutoCAD對象工作原理是相同。為了提高由自定義對象數(shù)據(jù)的使用效率,應(yīng)該為用戶提供編輯接口,使得用戶可以用程序批量處理數(shù)據(jù)。
如圖1、圖2所示,編碼屬性是禁用的,因?yàn)椴辉试S用戶隨意修改它,但是用戶可以通過程序修改編碼。
一般創(chuàng)建自定義實(shí)體的過程為:
(1)創(chuàng)建DBX工程和ARX工程。DBX工程用來管理自定義實(shí)體類,負(fù)責(zé)自定義實(shí)體的讀、寫、顯示等操作;ARX工程包含了程序入口點(diǎn),在ARX命令函數(shù)中創(chuàng)建自定義實(shí)體對象實(shí)例,并可以在AutoCAD中加載運(yùn)行。
(2)在“項(xiàng)目依賴項(xiàng)”中設(shè)置ARX工程依賴于DBX工程;
(3)如果想使自定義實(shí)體支持ActiveX自動化功能,還要為DBX工程添加ATL COM Wrapper對象;
(4)如果想在屬性面板中顯示自定義的屬性,必須在自定義實(shí)體類中實(shí)現(xiàn)subGetClassID函數(shù),然后在新生成的*_i.c頭文件中復(fù)制CLSID并將其賦值給subGetClassID函數(shù)的參數(shù)*pClsid,如:
由DBX工程生成的自定義實(shí)體不能在AutoCAD環(huán)境中獨(dú)立運(yùn)行,需要由ARX應(yīng)用程序創(chuàng)建實(shí)例對象并添加到CAD數(shù)據(jù)庫中;而COM Wrapper對象對自定義對象進(jìn)行二次封裝,為用戶提供編程接口。這樣用戶就可以很方便地訪問自定義對象的屬性和方法了。在CAD環(huán)境中,用戶通過屬性面板修改圖形屬性的操作,都是借助于COM Wrapper這個中間媒介來訪問自定義對象的;而有些操作,如拖拽夾點(diǎn)、平移、縮放等,則是直接訪問自定義對象,如圖3所示。
圖3 自定義對象工作流程
我們在ini文件中存儲每個要素的配置信息,如:
為自定義對象類添加TCHAR*類型的成員變量mCode,該變量用來標(biāo)識要素編碼;添加用于表示符號位置的 AcGePoint3d類型的成員變量 mCenter。在subWorldDraw函數(shù)中根據(jù)編碼從ini文件中讀取符號名稱,如高程點(diǎn)的符號名稱為SYM-DM-001,然后繪制符號:
其他成員變量根據(jù)圖形表現(xiàn)的需要添加,本例中的成員變量還包括:
理論上來講,AutoCAD內(nèi)部實(shí)體能夠?qū)崿F(xiàn)的功能,自定義實(shí)體都實(shí)現(xiàn)。例如,可以通過LISP/VBA等編程手段操作一般對象,那在自定義實(shí)體中如何實(shí)現(xiàn)呢?
(1)支持AutoLISP編程
我們經(jīng)常使用entget函數(shù)查看修改對象的屬性,如用語名(entget(car(entsel)))查看圖1所示的控制點(diǎn)的數(shù)據(jù)表:
((-1.<圖元名:7ed03d38>)(0."MYSYMBOL")(330.<圖元名:7ed01cf8>)(5."7D7")(100."AcDbEntity")(67.0)(410."Model")(8."0")(62.1)(100."CMySymbol")(90 .1)(1 ."1110101000")(10 217.633 193.896 156.72)(11
219.597 193.931 156.72)(210 0.0 0.0 1.0)(2 ."張灣嶺")(340.<圖元名:7ed01c88>)(40.1.0)(90.1)(41.0.0)(42 .1.0)(211 1.0 0.0 0.0))
在數(shù)據(jù)表中,我們可以根據(jù)DXF組碼進(jìn)行過濾選擇,如根據(jù)編碼進(jìn)行選擇:
(ssget"x"(list(cons 1"1110101000")))
這樣就可以在AutoLISP中建立選擇集進(jìn)行循環(huán)處理了。
要想在上述數(shù)據(jù)表中添加編碼、點(diǎn)名等成員變量信息,我們需要在自定義實(shí)體類的dxfInFields、dxfOut-Fields函數(shù)中讀取和寫入成員變量。
(2)支持VisualLISP編程
當(dāng)我們對自定義對象的屬性和方法進(jìn)行了COM封裝后,就可以通過VisualLISP操作自定義對象了。當(dāng)然在應(yīng)用VisualLISP函數(shù)前要先用vlax-ename->vla-object函數(shù)將實(shí)體名轉(zhuǎn)成對象。
要實(shí)現(xiàn)對自定義對象的COM封裝,需要以下幾步:
(1)首先要建立一個ATL對象類,該類要繼承幾個接口對象:IOPMPropertyExpander、IOPMPropertyExtensionImpl、IAcadEntityDispatchImpl;
(2)在IDL文件中編輯接口屬性和方法;
(3)在COM類中定義并實(shí)現(xiàn)接口屬性;
(4)在屬性映射表OPMPROP_MAP中添加自定義屬性入口;
(5)要改變屬性面板中文本框中的顯示名稱,需要在GetDisplayName(DISPID dispID,BSTR*pBstr)函數(shù)中對dispID的值為0x401的pBstr參數(shù)賦新值;
(6)屬性面板中要改變每個分類的名稱,需要在GetCategoryName函數(shù)中針對不同的PROPCAT參數(shù)值,修改BSTR參數(shù)的名稱;
(7)在Editable函數(shù)中控制屬性的可編輯性,在ShowProperty函數(shù)中控制屬性是否可見。
為了使自定義對象的屬性表達(dá)更加靈活,我們?yōu)樽远x對象定義了兩類屬性,一類是靜態(tài)的,即前文提到的COM包裝類中的屬性,另一類是動態(tài)屬性,用來存儲與圖形本身無關(guān)的屬性,如圖4中的“符號屬性”所示。
圖4 動態(tài)屬性
COM包裝類中的屬性直接存儲到對象自身數(shù)據(jù)表中,而動態(tài)屬性我們存儲在對象擴(kuò)展字典的擴(kuò)展記錄中。這樣在查詢的時候,可以根據(jù)擴(kuò)展記錄的關(guān)鍵字直接得到。如圖4所示,需要定義兩種用于生成動態(tài)屬性的類,一個是派生于IDynamicProperty接口的用于處理字符串?dāng)?shù)據(jù)類型的類;一個派生于IDynamicEnumProperty的用于處理枚舉類型的類。在處理枚舉類型動態(tài)屬性數(shù)據(jù)時,需要注意的是,OPM僅處理VT_I4類型的數(shù)據(jù),即LONG類型,所以在GetPropValueData(LONG index,VARIANT*pValue)函數(shù)中,pValue必須賦值為LONG類型,如存儲當(dāng)前ComboBox下拉列表的索引,或者存儲對象的ID等。
目前基于AutoCAD中的地形圖成圖軟件,只有基于自定義實(shí)體技術(shù)才能最大限度地保證要素的完整性、優(yōu)化數(shù)據(jù)組織方式。盡管軟件開發(fā)的難度大、周期長,但是對于它的研究仍然具有重要的意義。
[1]宋延杭,王川,李永宣.ObjectARX實(shí)用指南[M].北京:人民郵電出版社,1999
[2]老大中,趙占強(qiáng).AutoCAD 2000ARX二次開發(fā)實(shí)例精粹[M].北京:國防工業(yè)出版社,2001
[3]Charles McAuley.AutoCAD 2000ObjectARX編程指南[M].北京:機(jī)械工業(yè)出版社,2000
[4]張長勛.AutoCAD VisualLISP程序開發(fā)技術(shù)[M].北京:國防工業(yè)出版社,2005
[5]余承飛,方勇.AutoCAD 2000二次開發(fā)技術(shù)(Object-ARX)[M].北京:人民郵電出版社,1999
[6]Autodesk.ObjectARX開發(fā)指南.1999