楊艷林, 靖 晶, 劉廣寧, 王世昌
(1.中國地質(zhì)調(diào)查局 武漢地質(zhì)調(diào)查中心,武漢 430205; 2.中國地質(zhì)大學(xué)(武漢) 環(huán)境學(xué)院,武漢 430074)
MapGis軟件是水工環(huán)地質(zhì)調(diào)查中提交圖件及數(shù)據(jù)庫的專用軟件,而圖元屬性是MapGis管理數(shù)據(jù)的強項,它不再是簡單的紙質(zhì)圖形,而是圖形與屬性的融合,大大提升了圖件的信息量與實用價值,如屬性數(shù)據(jù)可為后期的空間分析、地下水水量與水質(zhì)評價等方面提供數(shù)據(jù)支撐。在水工環(huán)地質(zhì)調(diào)查過程中,獲得了大量野外調(diào)查點及點屬性的卡片(如水文地質(zhì)調(diào)查中的井點卡片),包括的屬性數(shù)據(jù)有:井位、井結(jié)構(gòu)、井開采、井水位水質(zhì)等,其數(shù)據(jù)項多達50項[1],而這些屬性數(shù)據(jù)最后都要包含在管理數(shù)據(jù)庫和編制圖件的空間數(shù)據(jù)庫中,才能進行成果提交。
通常在進行野外水工環(huán)地質(zhì)測繪時,每天都會將記錄的卡片數(shù)據(jù)錄入到數(shù)據(jù)庫中進行管理。當(dāng)野外測繪完成后,在進行成果圖件編制時,若采取一邊投點,一邊錄入屬性的方法,將會擠占技術(shù)人員大量寶貴的時間,而且也沒有充分利用管理數(shù)據(jù)庫中數(shù)據(jù)可導(dǎo)出再利用的特點,故非常有必要在數(shù)據(jù)庫與編圖之間架起一座橋梁,尤其是調(diào)查點與屬性數(shù)據(jù)的關(guān)聯(lián)。
在這方面,已有不少學(xué)者進行了相關(guān)研究,秦威[2]利用VC編程語言對MapGis進行二次開發(fā),完成了屬性數(shù)據(jù)的輸入;汪新慶等[3]在MapGis二次開發(fā)環(huán)境下,利用VC編程語言實現(xiàn)了屬性數(shù)據(jù)的邏輯檢查,提高了圖件檢查驗收的工作效率,并保證了數(shù)據(jù)的準(zhǔn)確性與可靠性;張厚泉[4]利用MapGis軟件中“投影變換”子系統(tǒng)內(nèi)的“用戶文件投影變換”命令實現(xiàn)了水井點圖元批量編圖;史文博[5]利用MapGis軟件討論了5種屬性連接的方法;張良紅等[6]利用MapGis提供的MFC類庫,完成了航點生成MapGis點文件的方法。綜觀目前的方法主要有三種:①利用MapGis的明碼文件對野外調(diào)查點進行投點,但不能將屬性數(shù)據(jù)一并進行導(dǎo)入;②利用MapGis平臺進行二次開發(fā),但不能解決同其他軟件數(shù)據(jù)的無縫轉(zhuǎn)換;③利用MapGis軟件提供的功能,需熟練地掌握MapGis軟件,也無法完成同其他軟件之間的數(shù)據(jù)共享。
目前,GIS軟件產(chǎn)品眾多,如ArcGis、MapInfo、AutoCAD、MapGis、GeoStar、SuperMap、CityStar等,不同軟件平臺之間的數(shù)據(jù)轉(zhuǎn)換越來越頻繁,特別是與MapGis數(shù)據(jù)之間的轉(zhuǎn)換;而不同的GIS系統(tǒng)對各種地質(zhì)現(xiàn)象的理解、描述方式、概念模型、數(shù)據(jù)結(jié)構(gòu)、實現(xiàn)手段等互不相同,且缺少統(tǒng)一的數(shù)據(jù)接口,雖然可以通過一些中間文件實現(xiàn)互轉(zhuǎn),但極易丟失屬性數(shù)據(jù),造成GIS數(shù)據(jù)之間共享困難,形成了人力、財力上的浪費,資源得不到有效地利用[7]。閆琰等[8]在研究以直接和間接轉(zhuǎn)換的方法實現(xiàn)ArcGis向MapGis軟件的數(shù)據(jù)格式轉(zhuǎn)換時,發(fā)現(xiàn)很難進行一次性批量轉(zhuǎn)換,數(shù)據(jù)易失真,圖形渲染易變樣,無法實現(xiàn)GIS數(shù)據(jù)的無損轉(zhuǎn)換;王星捷[9]以MapGis點文件的數(shù)據(jù)格式進行分析研究,并編制程序?qū)崿F(xiàn)了MapGis點文件的讀取實驗,但對屬性數(shù)據(jù)的處理未進行深入的研究。
鑒于此,為了充分發(fā)揮計算機的強大計算性能,從根本上解決:快速輸入野外采集的屬性數(shù)據(jù)、快速讀取前人調(diào)查點的屬性數(shù)據(jù)、MapGis多屬性數(shù)據(jù)快速成圖、打破不同GIS平臺之間的“信息孤島”、且不受MapGis平臺限制的接口程序等方面的問題,以及有效提高成果資料的信息化和服務(wù)能力,其關(guān)鍵是對MapGis點文件的分析,筆者將從MapGis點文件(無TIC點)及其屬性塊的數(shù)據(jù)結(jié)構(gòu)、存儲算法和關(guān)鍵環(huán)節(jié)等方面進行了詳細闡述,并且為了敘述的方面,對用到的數(shù)據(jù)結(jié)構(gòu)、函數(shù)或算法,都以Visual C++語言的形式列出。
MapGis點文件是以WT為后綴名的二進制文件,主要包括空間數(shù)據(jù)與屬性數(shù)據(jù)??臻g數(shù)據(jù)為字符串、文本、子圖、圓、弧段、圖片等五種類型,參考MapGis安裝目錄中的baseDefine.h文件,其數(shù)據(jù)結(jié)構(gòu)見表1~表6。屬性數(shù)據(jù)的數(shù)據(jù)類型多達17種,常用的主要有字符串(string)、短整型(short)、長整型(long)、浮點型(float)、雙精度型(double)、日期型和時間型等,屬性的個數(shù)不受限制[10]。
表1 MapGis點文件中字符串的數(shù)據(jù)結(jié)構(gòu)
表2 MapGis點文件中文本的數(shù)據(jù)結(jié)構(gòu)
表3 MapGis點文件中子圖數(shù)據(jù)結(jié)構(gòu)
表4 MapGis點文件中圓的數(shù)據(jù)結(jié)構(gòu)
表5 MapGis點文件中弧的數(shù)據(jù)結(jié)構(gòu)
表6 MapGis中圖片的數(shù)據(jù)結(jié)構(gòu)
利用UltraEdit工具打開點文件,并結(jié)合MapGis軟件對點文件的顯示以及前人的研究[9],可將點文件存儲的數(shù)據(jù)分為三個數(shù)據(jù)段:
1) 在前面的657個字節(jié),主要用于記錄點文件標(biāo)識(57 4D 41 50 60 44 32 32)、地圖參數(shù)(投影參數(shù)、單位及比例尺、圖幅范圍等)和點個數(shù)。
2) 緊接著的160字節(jié)是用于記錄16個數(shù)據(jù)塊的位置、長度,其中位置和長度都由4字節(jié)進行存儲,后2字節(jié)是結(jié)束標(biāo)記,值為-1,其數(shù)據(jù)結(jié)構(gòu)如表7所示。在MapGis6.7版本中,16個數(shù)據(jù)塊中目前主要使用的有5個:數(shù)據(jù)塊1主要是字符串、文本、弧、圓、圖片等繪制參數(shù),每個點由93個字節(jié)組成,其數(shù)據(jù)結(jié)構(gòu)見表8、表9、表10;數(shù)據(jù)塊2存放的是字符串ch_struct結(jié)構(gòu)中的str_text數(shù)據(jù)值,或文本text_struct結(jié)構(gòu)中的str_word數(shù)據(jù)值等,其長度由表8結(jié)構(gòu)中的len變量記錄;數(shù)據(jù)塊3是屬性數(shù)據(jù),屬性數(shù)據(jù)由屬性頭(348個字節(jié))、字段頭(39個字節(jié))、字段內(nèi)容(為變長度,字段頭中進行了定義)三部分組成;數(shù)據(jù)塊4是每個點的范圍數(shù)據(jù)(左下角坐標(biāo)和右上角坐標(biāo));數(shù)據(jù)塊5是點所在的圖層和圖元類型。
3)存放各數(shù)據(jù)塊的數(shù)據(jù),MapGis6.7版本中主要有5個。
表7 數(shù)據(jù)塊位置數(shù)據(jù)結(jié)構(gòu)
表8 MapGis點文件中點數(shù)據(jù)結(jié)構(gòu)
表9 PNT_INFO_UNION數(shù)據(jù)結(jié)構(gòu)
表10 D_DOT數(shù)據(jù)結(jié)構(gòu)
MapGis點文件的屬性數(shù)據(jù)是各類地物特征信息的具體記錄,主要用于描述實體要素的類別、特征和性質(zhì)。由于各領(lǐng)域的專業(yè)屬性差異甚大,不能用一個已知屬性集描述或概括所有應(yīng)用的專業(yè)屬性。在水文地質(zhì)調(diào)查中,記錄了大量井、泉等水文地質(zhì)點的屬性數(shù)據(jù),為了快速無縫地將這些屬性數(shù)據(jù)加入到成果圖件的空間數(shù)據(jù)庫中,需準(zhǔn)確掌握MapGis點文件屬性數(shù)據(jù)的存儲與讀取算法,而屬性數(shù)據(jù)結(jié)構(gòu)是關(guān)鍵。
基于MapGis點文件的二進制分析,屬性數(shù)據(jù)由屬性頭、字段頭和屬性數(shù)據(jù)三部分構(gòu)成,屬性頭的數(shù)據(jù)結(jié)構(gòu)(表11),占348個字節(jié),記錄的信息有:屬性長度(值為426+字段數(shù)×39)、點個數(shù)、字段個數(shù)、記錄長度等。為了便于理解和處理,將字段頭與屬性數(shù)據(jù)進行組合,其數(shù)據(jù)結(jié)構(gòu)如表12所示,包括了字段名,字段類型,字段字節(jié)長度,字段字符的長度、小數(shù)位數(shù)、編輯狀態(tài),及字段值等。其中字段類型有字符串型、浮點型、長整型、短整形等10余種,字段的屬性值則存放在fieldVal中。
表11 屬性頭數(shù)據(jù)結(jié)構(gòu)
表12 字段信息數(shù)據(jù)結(jié)構(gòu)
為了對多屬性數(shù)據(jù)進行讀/寫操作,將屬性頭數(shù)據(jù)結(jié)構(gòu)(記為INFO_HEAD)與字段信息數(shù)據(jù)結(jié)構(gòu)(記為FIELD_HEAD)進行組合,形成了屬性塊數(shù)據(jù)結(jié)構(gòu)(表13)。
表13 屬性塊的數(shù)據(jù)結(jié)構(gòu)
按照數(shù)據(jù)結(jié)構(gòu)中各數(shù)據(jù)類型進行讀寫,在進行讀寫之前,需對字段分配內(nèi)存空間,如fldEntry = newFIELD_HEAD[hd.numbfield];然后對屬性頭數(shù)據(jù)結(jié)構(gòu)中的字段數(shù)據(jù),可按fread/fwrite(&numbfield, sizeof(numfield), 1, pFile)(pFile為文件指針)進行讀寫操作;字段數(shù)據(jù)結(jié)構(gòu)中字段名,可按fread/fwrite(fieldname, 20, 1, pFile)進行讀寫操作(字段名的長度不能超過20);以及字段值可按fread/fwrite(fieldVal[iField], fieldlength, 1, pFile) (iField為第幾個字段)進行讀寫操作。
圖1 野外泉點部分屬性數(shù)據(jù)Fig.1 Paritial attribute data of the field springs
將野外調(diào)查卡片數(shù)據(jù)錄入管理數(shù)據(jù)庫中后,各種屬性數(shù)據(jù)可直接導(dǎo)出為Excel或TXT文件格式。編制圖件時,參考建庫指南[1],篩選目標(biāo)屬性數(shù)據(jù),通過類似于圖1所示的交互性對話框,將目標(biāo)屬性數(shù)據(jù)復(fù)制到對話框上,后將其寫出為所需的目標(biāo)點文件。
圖2 MapGis中屬性結(jié)構(gòu)設(shè)置Fig.2 Attribute structure settings in the MapGis
為了準(zhǔn)確寫出點文件,計算屬性數(shù)據(jù)塊的長度十分重要,按照前面的分析,其長度可分為3個部分,屬性頭、字段頭和屬性數(shù)據(jù),其中屬性頭長為348字節(jié),字段頭的長為39×字段個數(shù)(即hd.numbfield),而屬性數(shù)據(jù)的長度為:數(shù)據(jù)個數(shù)╳(標(biāo)識符 + 每個點數(shù)據(jù)中屬性的長度)(其中標(biāo)識的長度通常為一個字節(jié)),其中每個點數(shù)據(jù)的屬性長度可按式1進行計算。
len=0 for (int i = 0; i (1) 在MapGis中子圖號通常是用數(shù)字來進行標(biāo)識,而注釋通常是文字,故可依據(jù)這一點進行子圖號與注釋的判定。 在將點數(shù)據(jù)寫成MapGis點文件時,若某個字段為注釋,則注釋的長度是變長的,圖1中的地層時代,若在程序直接分配一個大大的內(nèi)存來進行存儲,當(dāng)然是可以,但這樣浪費了太多的內(nèi)存空間,故需要自動識別字符串的長度。通過遍歷操作地層時代,計算出該字段下的最大字符串長度,可按函數(shù)strlen(),或CString的GetLength()函數(shù)。為了處理中文的需要,常會用Unicode字符集,這時在計算字符串長度時,需利用WideCharToMultiByte函數(shù)將寬字節(jié)轉(zhuǎn)變?yōu)槎嘧止?jié)來計算字符串長度。 在使用MapGis軟件編輯點文件屬性結(jié)構(gòu)時,常會彈出圖2所示的對話框,經(jīng)常會誤認為字段長度就是浮點數(shù)的內(nèi)存長度,其實這是一種誤解。目前,在計算機內(nèi)部,浮點數(shù)主要分為單精度(float)和雙精度(double),其計算內(nèi)存大小分別是4位和8位,有效小數(shù)位數(shù)分別是7和16。而屬性結(jié)構(gòu)中的字段長度是指將浮點數(shù)轉(zhuǎn)為字符串時字符串的顯示長度,小數(shù)位數(shù)就是字符串中顯示小數(shù)的個數(shù)(圖3)。 圖3 浮點數(shù)內(nèi)存存儲及MapGis中顯示對比Fig.3 Floating-point memory storage and comparison in the MapGis 由前面分析知,當(dāng)某字段的數(shù)據(jù)類型為浮點型時,如圖1中的泉流量,若直接賦為雙精度類型,不會有問題,但從節(jié)約內(nèi)存的角度來看,這樣就有點欠妥,故需判定該字段是單精度還是雙精度,并計算出浮點數(shù)的長度和小數(shù)位數(shù)等數(shù)據(jù)。這時需要遍歷該字段的所有數(shù)據(jù),按字符串形式將數(shù)據(jù)讀入,計算字符串的長度,找到小數(shù)點并計算小數(shù)點位數(shù),通過遍歷找到最長字符串(記為nMaxLen,則msk_leng等于nMaxLen)和最長小數(shù)點位數(shù)長度(記為nDigit,則point_leng等于nDigit)。由于單精度浮點數(shù)的有效位數(shù)為7位,若nDigit小于7,則可賦為單精度浮點型(即fieldtype等于4,fieldlength等于4),否則為雙精度浮點型(即fieldtype等于5,fieldlength等于8)。當(dāng)然還需判定該數(shù)是否超過了單精度浮點數(shù)的范圍(-3.4E38~3.4E38);在水工環(huán)調(diào)查中,數(shù)據(jù)通常都在單精度浮點數(shù)范圍內(nèi)。 圖4 屬性值寫出過程及實例Fig.4 Attribute value writing process and example 短整型與長整型的主要區(qū)別是取值范圍和字節(jié)大小不同。短整形所能表示的整數(shù)域為-32 768~32 767,占2字節(jié)內(nèi)存;而長整型表示的整數(shù)域為-2 147 483 648~2 147 483 647,占4字節(jié)內(nèi)存。若某字段數(shù)據(jù)無小數(shù)點,則為整型數(shù),后通過遍歷判斷字段內(nèi)的數(shù)據(jù)是否在-32 768~32 767范圍內(nèi),若在范圍內(nèi),則為短整型(即fieldtype等于2,fieldlength等于2),否則為長整型(即fieldtype等于3,fieldlength等于4)。 確定了字段長度(fieldlength)后,就可以為屬性值(fieldVal)分配內(nèi)存,其大小為hd.num1×fieldlength。在進行屬性值寫出時,不能直接將屬性值(fieldVal存儲的)直接寫出,需將屬性值轉(zhuǎn)換為該字段的數(shù)據(jù)類型,并按字段數(shù)據(jù)類型進行存儲(圖4)。若在進行屬性值讀入時,則是圖4的逆過程。 通過多次MapGis軟件對時間、日期數(shù)據(jù)的讀入與寫出,確定了時間和日期的數(shù)據(jù)結(jié)構(gòu)類型分別為TIME_STR和DATE_STRU,所占內(nèi)存大小分別為10字節(jié)和4字節(jié)(表14、表15)。 表14 自定義時間數(shù)據(jù)結(jié)構(gòu) 表15 自定義日期數(shù)據(jù)結(jié)構(gòu) 根據(jù)MapGis點文件二進制分析,尤其在點文件屬性數(shù)據(jù)方面,采用面向?qū)ο罂梢暬Z言Visual C++,編制了MapGis點文件讀取與寫入程序,其讀取過程見函數(shù)ReadMapGisWTData;并為其研發(fā)了人機交互界面(圖2)。當(dāng)進行點文件生成時,通過設(shè)置點數(shù)和屬性數(shù),將點數(shù)據(jù)輸入到網(wǎng)格中,也可以直接將Excel表格中的數(shù)據(jù)復(fù)制到表格,點擊“導(dǎo)出”即可完成。當(dāng)進行點文件屬性編輯時,點擊“導(dǎo)入”即可讀入已有的點文件,并將點數(shù)據(jù)顯示在網(wǎng)格中,編輯修改后點擊“導(dǎo)出”生成點文件。并且也提供了點文件投影參數(shù)的設(shè)置。最后,將生成的點文件加載到MapGis軟件中,即可完成多屬性點數(shù)據(jù)的快速成圖。 通過對比分析基于交互式界面輸入的點數(shù)據(jù)與MapGis中的點屬性數(shù)據(jù),結(jié)果一致,表明前面對點文件分析和程序編寫的正確性(圖5)。在2018年江西省清溪村幅1:50 000水文地質(zhì)調(diào)查中,借助本程序,完成了井、泉、水文孔等水文地質(zhì)點的屬性數(shù)據(jù)從管理數(shù)據(jù)庫到空間數(shù)據(jù)庫的快速成圖,大大提高了成圖效率。 boolReadMapGisWTData(FILE* pFile) { ReadFileHead(pFile);//文件頭- 657個字節(jié)進行讀入 ReadDataHead(pFile);//數(shù)據(jù)頭- 160個字節(jié)進行讀入 SetSize(nLin_show);//分配數(shù)據(jù)內(nèi)存空間 fseek(pFile, position[0], SEEK_SET);//子圖數(shù)據(jù) char* old_locale = _strdup( setlocale(LC_CTYPE,NULL) ); setlocale( LC_CTYPE, "chs");//讀出中文 longpos = ftell(pFile); for (inti = 0; i { wtData[i].ReadData(pFile, position[1]);//讀取點數(shù)據(jù) pos += 93;fseek(pFile, pos, SEEK_SET);//文件指針 } setlocale( LC_CTYPE, old_locale); free( old_locale );//還原區(qū)域設(shè)定 fseek(pFile, position[2], SEEK_SET); wtAttData.ReadField(pFile, nLin_show);//讀取屬性數(shù)據(jù)段 fseek(pFile, position[3], SEEK_SET); for (inti = 0; i fseek(pFile, position[4], SEEK_SET);//點圖元數(shù)據(jù)段 for (inti = 0; i { fread(&layer[i], 2, 1, pFile); fread(&kind[i], 2, 1, pFile); } return 1; } 圖5 點數(shù)據(jù)寫入MapGis點文件中Fig.5 Data written to the MapGis point file 1)通過對MapGis點文件的剖析,將點文件存儲的數(shù)據(jù)分為三個數(shù)據(jù)段,并給出點文件中空間數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。 2)基于點文件屬性數(shù)據(jù)的分析,屬性數(shù)據(jù)由屬性頭、字段頭和屬性數(shù)據(jù)三部分構(gòu)成,給出了對應(yīng)的數(shù)據(jù)結(jié)構(gòu),并對屬性數(shù)據(jù)中各字段的讀寫進行了介紹。 3)針對屬性數(shù)據(jù)易誤解、準(zhǔn)確寫出易出錯、節(jié)省內(nèi)存空間等關(guān)鍵部分,如屬性數(shù)據(jù)的長度計算、注釋與子圖的自動識別、常用數(shù)據(jù)類型自動識別、浮點數(shù)據(jù)類型的判定、屬性數(shù)據(jù)的讀入與寫出、以及時間與日期數(shù)據(jù)結(jié)構(gòu)等方面進行了詳述,確保屬性數(shù)據(jù)的準(zhǔn)確寫出。 4)利用VC++語言,研發(fā)了界面友好,使用方便、快捷、操作性強的可視化界面,明顯降低了勞動強度,有效地提高了工作效率,更重要的是確保了屬性數(shù)據(jù)的準(zhǔn)確性和可靠性。 為了實現(xiàn)其它GIS系統(tǒng)的點、線、區(qū)等屬性數(shù)據(jù)向MapGis的無縫轉(zhuǎn)換,筆者還未對MapGis點文件中包含TIC點,以及線、區(qū)文件進行研究,這將是后面繼續(xù)研究的方向。4.2 子圖號與注釋自動識別
4.3 字符串長度
4.4 易被誤解的地方
4.5 小數(shù)位數(shù)及字段長度自動識別
4.6 長、短整型自動識別
4.7 屬性值快速讀/寫
4.8 時間、日期數(shù)據(jù)結(jié)構(gòu)
5 算法編制及實例應(yīng)用
6 結(jié)論與建議