劉凱程 胡雋杉
(1.東莞市測繪院,廣東 東莞 523000;2.漯河市土地與房屋勘查測繪隊(duì),河南 漯河 462000)
Shapefile文件的屬性數(shù)據(jù)存儲在與其根名相同的dbf文件中,CAD文件可以將圖元對象的屬性信息附加到與其關(guān)聯(lián)的擴(kuò)展數(shù)據(jù) (XData)中。在ArcGIS中,可以直接在圖層中添加CAD數(shù)據(jù),也可以將Shapefile圖形數(shù)據(jù)導(dǎo)出至CAD,但兩者之間不能直接進(jìn)行屬性數(shù)據(jù)的轉(zhuǎn)換。該文通過對Shapefile文件屬性列表中的關(guān)鍵詞段(數(shù)據(jù)類型為對象ID)和CAD圖形中圖元的對象ID(ObjectID)的對照研究,找出了二者之間的關(guān)聯(lián),進(jìn)而使其屬性數(shù)據(jù)能夠進(jìn)行相互轉(zhuǎn)換。
為了試驗(yàn)和驗(yàn)證,該文結(jié)合“TEST宗地圖 .dwg”文件的CAD 樣予以說明。該文件中的宗地圖用CASS軟件繪制,已經(jīng)添加了宗地號、權(quán)利人和地類號等屬性數(shù)據(jù)。為了試驗(yàn)方便,刪除了除界址線之外的所有圖元。實(shí)際上,CASS的宗地屬性數(shù)據(jù)就是附加在宗地圖形上的擴(kuò)展數(shù)據(jù),其中最基本的屬性數(shù)據(jù)存放在“SOUTH”應(yīng)用下。
為了進(jìn)行查驗(yàn)分析,用CAD自帶的VBA開發(fā)工具編寫一個宏“ElementInfo()”用來查詢圖元信息及擴(kuò)展數(shù)據(jù)。該宏通過訪問圖元的ObjectID屬性來獲取其對象ID,通過調(diào)用圖元的GetXData方法來獲取其擴(kuò)展數(shù)據(jù),最后調(diào)用MsgBox()函數(shù)顯示上述數(shù)據(jù)。
在CAD中打開文件“TEST宗地圖.dwg”,運(yùn)行宏ElementInfo(),選擇圖中的1個宗地界址線,將會彈出1個信息窗顯示該宗地的圖元對象ID及宗地屬性(圖1)。
圖1 CASS軟件宗地界址線的擴(kuò)展數(shù)據(jù)
第一行為該宗地的圖元對象ID值,數(shù)據(jù)類型為長整數(shù)(Long),在VBA中可通過訪問圖形對象的ObjectID屬性獲取。第2行之后為擴(kuò)展數(shù)據(jù)的組碼值類型和值,其中組碼值類型“1001” 為擴(kuò)展數(shù)據(jù)的注冊應(yīng)用名,“1000” 為擴(kuò)展數(shù)據(jù)中的ASCII 字符串,在VBA中可用GetXData方法將它們讀取到數(shù)組xtypeOut和xdataOut中??梢钥闯?,xdataOut(0)= “SOUTH”,是CASS軟件定義的一個應(yīng)用名,宗地的基本屬性數(shù)據(jù)存放在該應(yīng)用下;xdataOut(1)= “300000”是CASS軟件內(nèi)部識別宗地圖元的特殊標(biāo)志;xdataOut(2)為宗地編號,xdataOut(3)為權(quán)利人,xdataOut(4)為地類編碼[1]。
根據(jù)上述分析,可以編寫一段程序代碼將圖形中所有圖元的屬性信息及擴(kuò)展數(shù)據(jù)讀取出來,生成1個Excel表。在ArcGIS中,可以將該表與該CAD文件轉(zhuǎn)換的Shapefile文件屬性表相連接,進(jìn)而實(shí)現(xiàn)二者屬性數(shù)據(jù)的轉(zhuǎn)換[2]。
上面已經(jīng)介紹,在VBA中可用CAD元的ObjectID屬性 和GetXData方法讀取對象ID和擴(kuò)展數(shù)據(jù),為了在ArcGIS中與Shapefile屬性表相連接,需要將CAD圖形文件中所有的圖元信息全部讀取出來。為此,可以通過編寫宏“ExportXData()”來實(shí)現(xiàn)。該宏首先啟動Excel并創(chuàng)建一個工作薄,然后讀取CAD模型空間內(nèi)所有圖元的指定屬性和擴(kuò)展數(shù)據(jù),將其添加到第一個工作表,同時按讀取順序在第一列生成一個由0開始的序號。將該工作薄保存為“TEST宗地屬性表.xls”(圖2)。
圖2 CAD導(dǎo)出的宗地屬性表
在1個CAD文件中,各圖元的對象ID(ObjectID)和句柄(Handle)都是唯一的,對象ID 和唯一的句柄是引用對象的2個途徑。ObjectID值是十進(jìn)制整數(shù),是按照圖元創(chuàng)建的順序由小到大生成的。Handle值十六進(jìn)制字符串,轉(zhuǎn)換為十進(jìn)制整數(shù)后也是由小到大的順序。該文采用ObjectID引用對象[3]。
與Shapefile文件不同,CAD圖元的對象ID是不連續(xù)的整數(shù),為與Shapefile屬性表相關(guān)聯(lián),需要在CAD導(dǎo)出的Excel表中設(shè)置1個充當(dāng)主關(guān)鍵詞的字段,在該字段中按照ObjectID由小到大的順序確定主關(guān)鍵詞段的值:第一條記錄為0,第n條記錄為n-1。
該文實(shí)驗(yàn)數(shù)據(jù)中的主關(guān)鍵詞段名為“FID”,確定CAD圖元的“FID”字段值有2種方法。
方法1:將所有圖元對象加入一個選擇集(SelectionSet)中,通過遍歷該選擇集的辦法將ObjectID和其他擴(kuò)展數(shù)據(jù)導(dǎo)出為Excel表,按照ObjectID的升序進(jìn)行排序,將第一條記錄的FID值賦為0,以后各行依次+1即可。也可以在遍歷選擇集時采用倒序的方法,這樣導(dǎo)出的順序便是ObjectID由小到大的順序,就不用再排序了。
方法2:CAD的ModelSpace圖元集對象中包括了圖形中所有的圖元,圖元在ModelSpace中的排列順序就是ObjectID值由小到大的順序。因此,只需按順序遍歷ModelSpace,將圖元的ObjectID和其他擴(kuò)展數(shù)據(jù)導(dǎo)出到Excel表,同時將第一條記錄的FID值賦為0,以后各行依次+1即可。該文中的宏“ExportXData”采用的就是該方法[4]。
啟動ArcMap,新建空白地圖,把CAD樣該文件“TEST宗地圖.dwg”添加進(jìn)圖層。將面圖層“TEST宗地圖.dwg Polygon”導(dǎo)出為Shapefile文件“TEST宗地圖.shp”并添加進(jìn)來。打開“TEST宗地圖”圖層的屬性表,添加一個用于計算面積的字段“Area”進(jìn)行對比分析,數(shù)據(jù)類型選“雙精度型”,用“幾何計算”功能計算該出字段的面積值(圖3)。
對照圖2和圖3中的面積字段“Area”可以看出,CAD導(dǎo)出的“TEST宗地屬性表.xls”和ArcGIS中的“TEST宗地圖”屬性表所關(guān)聯(lián)圖元的排列順序是一致的,主關(guān)鍵詞“FID”也完全相同。這樣,在ArcGIS中就可以根據(jù)主關(guān)鍵詞將這2個屬性表連接起來。
圖3 ArcGIS中的宗地屬性表
將從CAD導(dǎo)出的Excel表添加到ArcGIS,然后用主關(guān)鍵詞段將其與Shapefile文件的屬性表進(jìn)行連接,具體操作如下。
在ArcGIS的圖層中添加“TEST宗地屬性表.xls”,添加時選擇第一個工作表“Sheet1$”。 在“TEST宗地圖”圖層上點(diǎn)擊右鍵,在彈出的下拉式菜單中點(diǎn)擊“連接和關(guān)聯(lián)”,接著點(diǎn)擊“連接…”。在彈出的“連接數(shù)據(jù)”對話框中“1.選擇該圖層中連接將基于的字段”選“FID”, “2.選擇此表中要作為連接基礎(chǔ)的字段”也選“FID”,其余選項(xiàng)取默認(rèn)值,點(diǎn)擊“確定”按鈕。
打開“TEST宗地圖”圖層的屬性表,可以看出2個屬性表已經(jīng)連接起來了。
將表“Sheet1$”中的宗地字段加入“TEST宗地圖.shp”文件的屬性中,可以采用如下3種方法。
方法1:在連接后的屬性表中添加需要加進(jìn)來的字段,定義好字段名和數(shù)據(jù)類型,然后利用字段計算器把“Sheet1$”中對應(yīng)的字段抄錄過來。
方法2:將連接后的屬性表導(dǎo)出為一個新的dbf文件,移除 “TEST宗地圖”圖層,在文件夾中刪除“TEST宗地圖.dbf”文件,將導(dǎo)出的dbf文件重命名為“TEST宗地圖.dbf”,最后在ArcGIS圖層中重新添加“TEST宗地圖.shp”。
方法3:將連接屬性后的“TEST宗地圖.shp”導(dǎo)出為1個新的Shapefile文件并添加到ArcGIS圖層中,移除 “TEST宗地圖”圖層,在文件夾中刪除根名為“TEST宗地圖”的所有文件,將導(dǎo)出的Shapefile系列文件的根名批量重命名為“TEST宗地圖”。
最后,打開屬性表,刪除掉不需要的字段。通過上述操作,就可以將CAD圖形的屬性和擴(kuò)展數(shù)據(jù)轉(zhuǎn)換為Shapefile文件的屬性表。
3.1.1 確保Shapefile的dbf文件為ANSI編碼
有時,Shapefile文件的dbf屬性表用Excel打開后中文會顯示為亂碼,這是因?yàn)镾hapefile文件不是ANSI格式??赏ㄟ^修改Windows注冊表解決該問題。
打開注冊表編輯器,定位到HKEY_CURRENT_USERSoftwareESRIDesktop 10.8(根據(jù)實(shí)際安裝的版本而定)。新建 “Common”項(xiàng),在其下再新建“CodePage”項(xiàng),新建字符串值,名稱為“dbfDefault”,健值為“ANSI”。 重新導(dǎo)出Shapefile文件,打開dbf文件就顯示正常了。導(dǎo)出后還要在注冊表中把“dbfDefault”的健值改為“UTF-8”,否則在ArcMap中打開的Shapefile文件屬性表的中文又變成了亂碼。
3.1.2 確保導(dǎo)出的CAD圖形為多段線
在ArcGIS中,由添加的CAD文件導(dǎo)出的Shapefile文件屬性表“Shape”字段中會包括“ZM”值,Z值是高程屬性,M值是其他屬性。包括“ZM”值的Shapefile文件導(dǎo)出為CAD后,線和面變成了三維多段線。三維多段線沒有面積屬性,多數(shù)情況下還需要將其變?yōu)槎喽尉€。CAD中沒有直接將三維多段線轉(zhuǎn)為多段線的工具,需要在轉(zhuǎn)換前將Shapefile圖形的“ZM”值去除掉。具體操作如下:1) 點(diǎn)擊主菜單“地理處理”,打開“ArcToolbox”工具箱,依次展開“數(shù)據(jù)管理工具”、“要素”,打開“復(fù)制要素”對話框。2) 在“輸入要素”組合框中選擇原Shapefile文件,在“輸出要素”文本框輸入目標(biāo)Shapefile文件位置和名,點(diǎn)擊“環(huán)境…”按鈕,打開“環(huán)境設(shè)置” 對話框。3) 將“輸出包括M值”和“輸出包括Z值”均設(shè)置為“Disabled”, 點(diǎn)擊“確定”按鈕。
返回“復(fù)制要素”對話框中點(diǎn)擊“確定”按鈕。
在ArcGIS中,Shapefile文件導(dǎo)出的CAD圖形并沒有包括圖元所關(guān)聯(lián)的屬性數(shù)據(jù)。
可以采取如下2種模式存儲CAD屬性數(shù)據(jù):1) 用ADO建立CAD與外部數(shù)據(jù)庫dbf表的連接。但這種連接在CAD存儲位置發(fā)生改變時會失效,須重新設(shè)置連接的數(shù)據(jù)源。2) 直接將屬性信息存儲在CAD圖元的擴(kuò)展數(shù)據(jù)中。在這種模式中,屬性信息是附加在CAD圖元上的,是CAD圖元的組成部分,會隨CAD圖形的復(fù)制、轉(zhuǎn)移而攜帶。在CAD二次開發(fā)中一般多采用這種模式,該文介紹的就是這種模式[5]。
Shapefile文件的屬性數(shù)據(jù)實(shí)際上存儲在與其根名相同的dbf文件中,其與Shapefile之間的關(guān)聯(lián)主要是靠數(shù)據(jù)類型為“對象ID”的主關(guān)鍵詞段,這個字段的名字一般為“FID” 或“OBJECTID”。 這個dbf文件中每條記錄的主關(guān)鍵詞段值對應(yīng)一個Shapefile圖形的對象ID。在一個Shapefile文件中,各圖形的對象ID是從0開始的連續(xù)的整數(shù)。
將Shapefile的dbf文件中的記錄按主關(guān)鍵詞段的升序進(jìn)行排序,在CAD中打開導(dǎo)出的CAD文件,逐條讀取dbf文件記錄,按照CAD圖元ObjectID的升序用SetXData方法寫入其擴(kuò)展數(shù)據(jù)中,即可實(shí)現(xiàn)Shapefile到CAD的屬性轉(zhuǎn)換。如下2種方法均可實(shí)現(xiàn)上述目的。
方法1:將dbf導(dǎo)入一個數(shù)據(jù)庫中,然后再通過ADO連接訪問該dbf表,讀取表中的記錄寫入CAD圖元的擴(kuò)展數(shù)據(jù)中。這種方法需要安裝相應(yīng)的數(shù)據(jù)庫管理軟件。
方法2:這是1個比較簡單的方法。在Excel中直接打開dbf文件,按主關(guān)鍵詞段的升序?qū)ζ溥M(jìn)行排序,然后逐行讀取Excel數(shù)據(jù),按照CAD圖元ObjectID屬性值由小到大的順序?qū)懭肫鋽U(kuò)展數(shù)據(jù)中。
該文采用的是方法2,并為此編寫了宏“ImportXData()”來輔助實(shí)現(xiàn)。該宏通過遍歷Eccel活動工作表中除標(biāo)題行外的所有行,讀取指定單元格數(shù)據(jù),然后以該順序號為索引,用CAD模型空間對象ModelSpace的Item()方法訪問相應(yīng)的圖元,為該圖元附加擴(kuò)展數(shù)據(jù)。下面是一個操作實(shí)例。
(1)在ArcMap中添加“TEST宗地圖.shp”,將其導(dǎo)出為CAD文件“TEST宗地圖1.dwg”。
(2)在Excel中打開“TEST宗地圖.dbf”, 按“FID”字段的升序?qū)ζ溥M(jìn)行排序。
(3)運(yùn)行宏“ImportXData()”,將Excel數(shù)據(jù)寫入CAD。
經(jīng)上述操作, Shapefile的dbf文件數(shù)據(jù)被導(dǎo)入了對應(yīng)的CAD圖元擴(kuò)展數(shù)據(jù)中。用宏“ElementInfo()”查詢圖元信息,與ArcMap中識別的圖形屬性進(jìn)行對比,會發(fā)現(xiàn)二者是一一對應(yīng)的。
筆者通過上述文件的分析和代碼演示,向大家展示了怎樣用VBA程序?qū)hapefile圖形及其屬性數(shù)據(jù)轉(zhuǎn)換成CAD圖形及擴(kuò)展數(shù)據(jù)的一般過程。通過該文中實(shí)際運(yùn)用,證實(shí)該方法確實(shí)可行可靠,既方便又靈活,可以滿足我們很多個性化的需求。希望該文能為今后大家解決這類問題提供一個思路。