劉凱程 胡雋杉
(1.東莞市測繪院,廣東 東莞 523000;2.漯河市土地與房屋勘查測繪隊,河南 漯河 462000)
Shapefile文件的屬性數據存儲在與其根名相同的dbf文件中,CAD文件可以將圖元對象的屬性信息附加到與其關聯的擴展數據 (XData)中。在ArcGIS中,可以直接在圖層中添加CAD數據,也可以將Shapefile圖形數據導出至CAD,但兩者之間不能直接進行屬性數據的轉換。該文通過對Shapefile文件屬性列表中的關鍵詞段(數據類型為對象ID)和CAD圖形中圖元的對象ID(ObjectID)的對照研究,找出了二者之間的關聯,進而使其屬性數據能夠進行相互轉換。
為了試驗和驗證,該文結合“TEST宗地圖 .dwg”文件的CAD 樣予以說明。該文件中的宗地圖用CASS軟件繪制,已經添加了宗地號、權利人和地類號等屬性數據。為了試驗方便,刪除了除界址線之外的所有圖元。實際上,CASS的宗地屬性數據就是附加在宗地圖形上的擴展數據,其中最基本的屬性數據存放在“SOUTH”應用下。
為了進行查驗分析,用CAD自帶的VBA開發工具編寫一個宏“ElementInfo()”用來查詢圖元信息及擴展數據。該宏通過訪問圖元的ObjectID屬性來獲取其對象ID,通過調用圖元的GetXData方法來獲取其擴展數據,最后調用MsgBox()函數顯示上述數據。
在CAD中打開文件“TEST宗地圖.dwg”,運行宏ElementInfo(),選擇圖中的1個宗地界址線,將會彈出1個信息窗顯示該宗地的圖元對象ID及宗地屬性(圖1)。

圖1 CASS軟件宗地界址線的擴展數據
第一行為該宗地的圖元對象ID值,數據類型為長整數(Long),在VBA中可通過訪問圖形對象的ObjectID屬性獲取。第2行之后為擴展數據的組碼值類型和值,其中組碼值類型“1001” 為擴展數據的注冊應用名,“1000” 為擴展數據中的ASCII 字符串,在VBA中可用GetXData方法將它們讀取到數組xtypeOut和xdataOut中。可以看出,xdataOut(0)= “SOUTH”,是CASS軟件定義的一個應用名,宗地的基本屬性數據存放在該應用下;xdataOut(1)= “300000”是CASS軟件內部識別宗地圖元的特殊標志;xdataOut(2)為宗地編號,xdataOut(3)為權利人,xdataOut(4)為地類編碼[1]。
根據上述分析,可以編寫一段程序代碼將圖形中所有圖元的屬性信息及擴展數據讀取出來,生成1個Excel表。在ArcGIS中,可以將該表與該CAD文件轉換的Shapefile文件屬性表相連接,進而實現二者屬性數據的轉換[2]。
上面已經介紹,在VBA中可用CAD元的ObjectID屬性 和GetXData方法讀取對象ID和擴展數據,為了在ArcGIS中與Shapefile屬性表相連接,需要將CAD圖形文件中所有的圖元信息全部讀取出來。為此,可以通過編寫宏“ExportXData()”來實現。該宏首先啟動Excel并創建一個工作薄,然后讀取CAD模型空間內所有圖元的指定屬性和擴展數據,將其添加到第一個工作表,同時按讀取順序在第一列生成一個由0開始的序號。將該工作薄保存為“TEST宗地屬性表.xls”(圖2)。

圖2 CAD導出的宗地屬性表
在1個CAD文件中,各圖元的對象ID(ObjectID)和句柄(Handle)都是唯一的,對象ID 和唯一的句柄是引用對象的2個途徑。ObjectID值是十進制整數,是按照圖元創建的順序由小到大生成的。Handle值十六進制字符串,轉換為十進制整數后也是由小到大的順序。該文采用ObjectID引用對象[3]。
與Shapefile文件不同,CAD圖元的對象ID是不連續的整數,為與Shapefile屬性表相關聯,需要在CAD導出的Excel表中設置1個充當主關鍵詞的字段,在該字段中按照ObjectID由小到大的順序確定主關鍵詞段的值:第一條記錄為0,第n條記錄為n-1。
該文實驗數據中的主關鍵詞段名為“FID”,確定CAD圖元的“FID”字段值有2種方法。
方法1:將所有圖元對象加入一個選擇集(SelectionSet)中,通過遍歷該選擇集的辦法將ObjectID和其他擴展數據導出為Excel表,按照ObjectID的升序進行排序,將第一條記錄的FID值賦為0,以后各行依次+1即可。也可以在遍歷選擇集時采用倒序的方法,這樣導出的順序便是ObjectID由小到大的順序,就不用再排序了。
方法2:CAD的ModelSpace圖元集對象中包括了圖形中所有的圖元,圖元在ModelSpace中的排列順序就是ObjectID值由小到大的順序。因此,只需按順序遍歷ModelSpace,將圖元的ObjectID和其他擴展數據導出到Excel表,同時將第一條記錄的FID值賦為0,以后各行依次+1即可。該文中的宏“ExportXData”采用的就是該方法[4]。
啟動ArcMap,新建空白地圖,把CAD樣該文件“TEST宗地圖.dwg”添加進圖層。將面圖層“TEST宗地圖.dwg Polygon”導出為Shapefile文件“TEST宗地圖.shp”并添加進來。打開“TEST宗地圖”圖層的屬性表,添加一個用于計算面積的字段“Area”進行對比分析,數據類型選“雙精度型”,用“幾何計算”功能計算該出字段的面積值(圖3)。
對照圖2和圖3中的面積字段“Area”可以看出,CAD導出的“TEST宗地屬性表.xls”和ArcGIS中的“TEST宗地圖”屬性表所關聯圖元的排列順序是一致的,主關鍵詞“FID”也完全相同。這樣,在ArcGIS中就可以根據主關鍵詞將這2個屬性表連接起來。

圖3 ArcGIS中的宗地屬性表
將從CAD導出的Excel表添加到ArcGIS,然后用主關鍵詞段將其與Shapefile文件的屬性表進行連接,具體操作如下。
在ArcGIS的圖層中添加“TEST宗地屬性表.xls”,添加時選擇第一個工作表“Sheet1$”。 在“TEST宗地圖”圖層上點擊右鍵,在彈出的下拉式菜單中點擊“連接和關聯”,接著點擊“連接…”。在彈出的“連接數據”對話框中“1.選擇該圖層中連接將基于的字段”選“FID”, “2.選擇此表中要作為連接基礎的字段”也選“FID”,其余選項取默認值,點擊“確定”按鈕。
打開“TEST宗地圖”圖層的屬性表,可以看出2個屬性表已經連接起來了。
將表“Sheet1$”中的宗地字段加入“TEST宗地圖.shp”文件的屬性中,可以采用如下3種方法。
方法1:在連接后的屬性表中添加需要加進來的字段,定義好字段名和數據類型,然后利用字段計算器把“Sheet1$”中對應的字段抄錄過來。
方法2:將連接后的屬性表導出為一個新的dbf文件,移除 “TEST宗地圖”圖層,在文件夾中刪除“TEST宗地圖.dbf”文件,將導出的dbf文件重命名為“TEST宗地圖.dbf”,最后在ArcGIS圖層中重新添加“TEST宗地圖.shp”。
方法3:將連接屬性后的“TEST宗地圖.shp”導出為1個新的Shapefile文件并添加到ArcGIS圖層中,移除 “TEST宗地圖”圖層,在文件夾中刪除根名為“TEST宗地圖”的所有文件,將導出的Shapefile系列文件的根名批量重命名為“TEST宗地圖”。
最后,打開屬性表,刪除掉不需要的字段。通過上述操作,就可以將CAD圖形的屬性和擴展數據轉換為Shapefile文件的屬性表。
3.1.1 確保Shapefile的dbf文件為ANSI編碼
有時,Shapefile文件的dbf屬性表用Excel打開后中文會顯示為亂碼,這是因為Shapefile文件不是ANSI格式。可通過修改Windows注冊表解決該問題。
打開注冊表編輯器,定位到HKEY_CURRENT_USERSoftwareESRIDesktop 10.8(根據實際安裝的版本而定)。新建 “Common”項,在其下再新建“CodePage”項,新建字符串值,名稱為“dbfDefault”,健值為“ANSI”。 重新導出Shapefile文件,打開dbf文件就顯示正常了。導出后還要在注冊表中把“dbfDefault”的健值改為“UTF-8”,否則在ArcMap中打開的Shapefile文件屬性表的中文又變成了亂碼。
3.1.2 確保導出的CAD圖形為多段線
在ArcGIS中,由添加的CAD文件導出的Shapefile文件屬性表“Shape”字段中會包括“ZM”值,Z值是高程屬性,M值是其他屬性。包括“ZM”值的Shapefile文件導出為CAD后,線和面變成了三維多段線。三維多段線沒有面積屬性,多數情況下還需要將其變為多段線。CAD中沒有直接將三維多段線轉為多段線的工具,需要在轉換前將Shapefile圖形的“ZM”值去除掉。具體操作如下:1) 點擊主菜單“地理處理”,打開“ArcToolbox”工具箱,依次展開“數據管理工具”、“要素”,打開“復制要素”對話框。2) 在“輸入要素”組合框中選擇原Shapefile文件,在“輸出要素”文本框輸入目標Shapefile文件位置和名,點擊“環境…”按鈕,打開“環境設置” 對話框。3) 將“輸出包括M值”和“輸出包括Z值”均設置為“Disabled”, 點擊“確定”按鈕。
返回“復制要素”對話框中點擊“確定”按鈕。
在ArcGIS中,Shapefile文件導出的CAD圖形并沒有包括圖元所關聯的屬性數據。
可以采取如下2種模式存儲CAD屬性數據:1) 用ADO建立CAD與外部數據庫dbf表的連接。但這種連接在CAD存儲位置發生改變時會失效,須重新設置連接的數據源。2) 直接將屬性信息存儲在CAD圖元的擴展數據中。在這種模式中,屬性信息是附加在CAD圖元上的,是CAD圖元的組成部分,會隨CAD圖形的復制、轉移而攜帶。在CAD二次開發中一般多采用這種模式,該文介紹的就是這種模式[5]。
Shapefile文件的屬性數據實際上存儲在與其根名相同的dbf文件中,其與Shapefile之間的關聯主要是靠數據類型為“對象ID”的主關鍵詞段,這個字段的名字一般為“FID” 或“OBJECTID”。 這個dbf文件中每條記錄的主關鍵詞段值對應一個Shapefile圖形的對象ID。在一個Shapefile文件中,各圖形的對象ID是從0開始的連續的整數。
將Shapefile的dbf文件中的記錄按主關鍵詞段的升序進行排序,在CAD中打開導出的CAD文件,逐條讀取dbf文件記錄,按照CAD圖元ObjectID的升序用SetXData方法寫入其擴展數據中,即可實現Shapefile到CAD的屬性轉換。如下2種方法均可實現上述目的。
方法1:將dbf導入一個數據庫中,然后再通過ADO連接訪問該dbf表,讀取表中的記錄寫入CAD圖元的擴展數據中。這種方法需要安裝相應的數據庫管理軟件。
方法2:這是1個比較簡單的方法。在Excel中直接打開dbf文件,按主關鍵詞段的升序對其進行排序,然后逐行讀取Excel數據,按照CAD圖元ObjectID屬性值由小到大的順序寫入其擴展數據中。
該文采用的是方法2,并為此編寫了宏“ImportXData()”來輔助實現。該宏通過遍歷Eccel活動工作表中除標題行外的所有行,讀取指定單元格數據,然后以該順序號為索引,用CAD模型空間對象ModelSpace的Item()方法訪問相應的圖元,為該圖元附加擴展數據。下面是一個操作實例。
(1)在ArcMap中添加“TEST宗地圖.shp”,將其導出為CAD文件“TEST宗地圖1.dwg”。
(2)在Excel中打開“TEST宗地圖.dbf”, 按“FID”字段的升序對其進行排序。
(3)運行宏“ImportXData()”,將Excel數據寫入CAD。
經上述操作, Shapefile的dbf文件數據被導入了對應的CAD圖元擴展數據中。用宏“ElementInfo()”查詢圖元信息,與ArcMap中識別的圖形屬性進行對比,會發現二者是一一對應的。
筆者通過上述文件的分析和代碼演示,向大家展示了怎樣用VBA程序將Shapefile圖形及其屬性數據轉換成CAD圖形及擴展數據的一般過程。通過該文中實際運用,證實該方法確實可行可靠,既方便又靈活,可以滿足我們很多個性化的需求。希望該文能為今后大家解決這類問題提供一個思路。