1.前言 前一段公司出于成本和效率的原因,要求在我們的產(chǎn)品中用開源的GIS組件來代替以前使用的MapX,經(jīng)過一段時間的查找,我發(fā)現(xiàn)了MapWinGIS這個東西基本可以滿足我們的要求。經(jīng)過幾天的摸索,我寫了這篇文章,希望能對其他使用MapWinGIS的人有所幫助。我平常接觸GIS很少,也最多就是在開發(fā)系統(tǒng)中偶爾用到MapX,很多基本概念也不了解,所以可能有很多錯誤的地方,忘見諒。 2.MapWinGIS簡單介紹 MapWinGIS是一個開源的ActiveX組件,功能上類似MapX,開發(fā)人員可以利用這個ActiveX組件在自己的系統(tǒng)中完成GIS的相關功能,例如地圖,IMAGE,GRID的顯示;在圖層上標繪點,線,圖形;計算長度,存取GIS數(shù)據(jù)等相關工作. 它的主要功能包括: 直接打開,編輯,保存Image,Grid,Shapfile,TIN,DBF格式的文件 在地圖中對圖形進行瀏覽,標注,設置顏色等信息。 在地圖中進行空間數(shù)據(jù)查詢 動態(tài)的在圖層上標繪空間數(shù)據(jù)。 存取地圖中的相關數(shù)據(jù)。 對不同的格式進行轉(zhuǎn)換,例如從TIN到GIRD等。 MapWinGIS團隊的開發(fā)人員似乎主要來自愛荷華大學,MapWinGIS按Mozilla Public License 1.1.發(fā)布。在MapWinGIS 的基礎上,他們又開發(fā)了MapWindow GIS,這是一套GIS系統(tǒng),用戶可以直接通過它瀏覽數(shù)據(jù),并通過一系列插件來完成其他功能。還有一套MapWinX,是DOTNET平臺下的一個輔助工具。 MapWinGIS 是在VS2003下由VC開發(fā)而成,MapWindow GIS 是VB.NET開發(fā)的。其中MapWinGIS 代碼大約有15萬行,大約50%的注釋率。在MapWindow的網(wǎng)站提供了一個VB6的簡單例子代碼,也可以通過觀看MapWindow GIS來學習它的一些更高級的功能。 它的官方網(wǎng)站是 [www.mapwindow.org] ,在網(wǎng)站上提供了二進制程序下載,源代碼下載,并且有相關的論壇和文檔,資料算是比較豐富的,似乎好像有一個開發(fā)人員是華人,所以還有個中文論壇,就是帖子太少。 3.文件格式的轉(zhuǎn)換 由于用戶提供的是MapInfo的TAB格式的底圖,而MapWinGIS不能處理該格式的文件,所以必須要進行相關的轉(zhuǎn)換工作,具體做法為:首先將MapInfo的TAB格式的底圖轉(zhuǎn)換為MapInfo的MIF格式(MIF格式是MapInfo的文本交換格式文件).然后再將MIF文件格式轉(zhuǎn)換為MapWinGIS可以直接讀取的SHP格式(SHP格式是ESRI公司定義的空間數(shù)據(jù)文件格式). 我們可以用MITAB將TAB格式轉(zhuǎn)換為MIF格式,MITAB是一套開源的C++庫(具體請參見[mitab.maptools.org]),用戶可以根據(jù)這個庫在自己的應用程序中實現(xiàn)轉(zhuǎn)換,MITAB也提供了一個命令行工具tab2tab.exe 直接將TAB格式轉(zhuǎn)換為MIF格式,具體命令為: tab2tab source.tab dist.mif 在得到MIF文件后,可以用OGR將MIF格式轉(zhuǎn)換為SHP格式,OGR也是一套開源的C++庫(具體請參見[ogr.maptools.org]),用戶可以根據(jù)這個庫在自己的應用程序中實現(xiàn)轉(zhuǎn)換,ORG也提供了一個命令行工具ogr2ogr.ext來實現(xiàn)轉(zhuǎn)換,轉(zhuǎn)換的命令為: ogr2ogr -f "ESRI Shapefile" dist.shp source.mif 在根據(jù)TAB文件得到SHP文件后,我們就可以使用MapWinGIS了。 4.對象介紹 在MapWinGIS中,最常用的對象有如下幾個: Map:MapWinGIS最主要的對象,用于顯示Grid,Image和Shapefile,它管理所有的圖層,并響應鼠標操作,類似于MapX中的Map對象。 Shapefile:一個圖層對象,可以由用戶創(chuàng)建,也可以從圖層文件中生成(SHP文件),類似于MapX中的Layer對象,可以在該對象上標點,標線,標圖形等。 Shape:一個圖形對象,可以是點,先,面等。 Point:代表了一個坐標點 Field:存儲相關地理信息的一個字段,類似于DBF 表中的字段。 Table:存儲相關地理信息的一個表。 5.MapWinGIS的使用 MapWinGIS在VB下使用的比較簡單,網(wǎng)站上也提供了VB的例子,已經(jīng)很詳細了,我這里主要講一下在VC中的調(diào)用和一些我使用上的碰到的一些問題 5.1 調(diào)用方式 在VC6中,似乎由于一些特殊原因(原因?qū)⒃诤竺嬲劶埃?,無法象使用其他ActiveX一樣,直接從Project->Add To Project ->Components and Controls 中選擇MapWinGIS.ocx,生成相關的封裝類,它將報一個錯,錯誤是"The ActiveX Control is not registered properly ,or its type library version number is incorrect…"。因而只能從Gallery/ Registered ActiveX Controls中選擇已經(jīng)注冊的Map Control加入到這個項目中,但用這種方式只能生成Map對象的CMap封裝類,其他對象無法生成封裝類。如果從Type Library 中生成"COleDispatchDriver"的子類封裝的化,則在調(diào)用相關的封裝類的方法或?qū)傩詴r,例如CShapefile的Open方法,則會產(chǎn)生一個異常,異常的消息代碼為"8002801D"。關于這個異常,MS有一個相關的解釋,大致就是ATL的版本似乎不對,前面無法正常插入這個OCX 對象大概也是這個原因,這篇文章的地址為:"http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B221792"。在MapWindow的論壇上我也看到了有人提出過這個問題,大概也有人碰到過。所以,我試出來正確的調(diào)用方式是使用"#import "MapWinGIS.ocx"rename_namespace("mapWindow") rename("GetObject", "MapWinGISGetObject")",為了省事,仍然可用前面插入OCX的方法創(chuàng)建一個CMap的封裝類,使用Map對象時直接調(diào)用這個Map的封裝類,而其他對象使用IXXXXPtr的smart pointer,下面是調(diào)用過程: 1.在Project->Add To Project ->Components and Controls插入OCX對象,生成CMap1封裝類 2.在Stdafx頭文件中增加#import "MapWinGIS.ocx" rename_namespace("mapWindow") rename("GetObject", "MapWinGISGetObject")" 3.創(chuàng)建一個資源ID,選擇View菜單中的Resource Symbols,創(chuàng)建一個新的資源ID,命名為IDC_MAP 4.在View的頭文件中,Include產(chǎn)生的封裝類頭文件,然后加入封裝類的對象,如下代碼: #include "Map.h" Class CTestMapWindowView :public CView { Protected: CMap1 m_Map; } 5.在視圖(假設為文檔-視圖結(jié)構(gòu))的應用中對View類創(chuàng)建WM_CREATE的消息映射函數(shù),加入如下代碼: if(m_Map.Create(NULL, WS_VISIBLE, CRect(0,0,400,400), this, IDC_MAP) == false){ return -1; } 6.在View類中創(chuàng)建WM_SIZE的消息映射函數(shù),加入如下代碼 void CTestMapWindowView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here m_Map.Resize(cx,cy); } 這樣,應用程序的框架基本完成,可以編譯,運行了。 5.2 加入圖層 由于在圖層Shapefile對象中使用了smart pointer進行封裝,因而加入圖層的代碼為 mapWindow::IShapefilePtr sf; HRESULT hr=sf.CreateInstance("MapWinGIS.Shapefile"); if (!SUCCEEDED(hr)){ return ; } USES_CONVERSION; //打開圖層文件 if(!sf->Open(A2BSTR("C:\\temp\\testgis\\shp\\11.shp"),NULL)){ return ; } //將設置顏色,標簽等信息,將圖層加入到Map中 long hanlde=m_Map.AddLayer(sf,true); m_Map.SetShapeLayerFillColor(handle,RGB((255-1)*rand(),(255-1)*rand(),(255-1)*rand())); m_Map.SetShapeLayerLineColor(handle,RGB((255-1)*rand(),(255-1)*rand(),(255-1)*rand())); m_Map.SetLayerLabelsVisible(handle,TRUE); 5.3 處理事件 要處理MapWinGIS的事件,需要創(chuàng)建一個事件槽(eventsink).具體方法如下,在View類的頭文件中,在DECLARE_MESSAGE_MAP()行下加入"DECLARE_EVENTSINK_MAP()" ,在CPP文件中加入如下代碼: BEGIN_EVENTSINK_MAP(CTestMapWindowView,CView) END_EVENTSINK_MAP() 為了響應MouseMove事件,在上述兩行代碼中加入如下代碼 ON_EVENT(CTestMapWindowView,IDC_MAP,0x03,OnMouseMove,VTS_I2 VTS_I2 VTS_I4 VTS_I4) 然后對CTestMapWindowView 類增加一個方法,函數(shù)聲明為: afx_msg void OnMouseMove(short _button,short _shift,long _x,long _y); 需要說明的是,在MapWinGIS中,為了能夠響應事件,必須在調(diào)用SetSendMouseMove(true)后才能響應鼠標移動事件,其他響應事件也是如此類推。 5.4改變顯示位置 在用戶希望地圖能夠自動漫游時,先調(diào)用Map對象的GetExtents對象得到Map的Extents 對象,然后調(diào)用Extents的對象的SetBounds來設置相關邊界,最后調(diào)用Map對象的SetExtents將這個Extents對象設置到Map對象中. 5.5 動態(tài)標繪 當用戶希望比較頻繁的動態(tài)標繪數(shù)據(jù)時,可以使用NewDrawing來創(chuàng)建一個繪畫層,然后調(diào)用DrawPoint ,DrawLine 或DrawPolygon 來在剛才的創(chuàng)建的層上標出點,線和多邊形。用ClearDrawing可以清除在這個層上所繪制的所有圖形,對于動態(tài)軌跡的顯示,就是在調(diào)用Draw后,用ClearDrawing清除,然后再重畫相應的軌跡。 用戶可以多次調(diào)用NewDrawing來創(chuàng)建新的繪畫層,對新的繪畫層上的相關操作并不影響到其他已經(jīng)創(chuàng)建的繪畫層。用戶可以調(diào)用ClearDrawing來清除指定的繪畫層上所有的圖形。但是,在創(chuàng)建了新的繪畫層后,無法對其他的繪畫層再進行任何繪畫操作;同時在調(diào)用了Draw后,也無法對所繪制的對象進行操作。唯一可用的是可以可以對剛才創(chuàng)建的對象進行設置一個Key,對剛才繪制的對象設置一個字符串,并可以讀取這個字符串。但是無法得到以前設置的其他對象的字符串。 5.6 動態(tài)繪制圖層 除了用NewDrawing來創(chuàng)建一個繪畫圖層外,還可以動態(tài)的創(chuàng)建一個Shapefile,在這個Shapefile上進行點,線,多邊形的繪制操作,在創(chuàng)建這個圖層過程中可以增加其他附加數(shù)據(jù)。即增加一個或若干個Field,在插入一個Shape后,可以指定在Field上插入該行的數(shù)據(jù)。在該圖層上,所有的圖形對象均可進行操作。 5.7 ShapefileColorBreak對象和ShapefileColorScheme對象 在創(chuàng)建ShapefileColorBreak對象和ShapefileColorScheme對象時,他們的ProgID分別為"MapWinGIS.ShapefileLegendBreak"和"MapWinGIS.ShapefileLegend",而不是"MapWinGIS.ShapefileColorBreak"和"MapWinGIS.ShapefileColorSchema"。在一開始我想當然的人為對象的名字就是ProgId的名字,后來發(fā)現(xiàn)不對,這里提醒一下。 6.其他說明 MapWinGIS的顯示速度同MapX相比快幾倍個數(shù)量級左右,我曾經(jīng)做過試驗,如果在圖上標繪100萬個點,如果使用MapX,大約要5-10分鐘,如果使用MapWinGIS,在Shapefile上繪制要1分鐘左右,使用NewDraw則更快。 可能是由于SHP本身格式的一些原因,一些MapInfo地圖中特有的信息,例如鐵路線,特殊標記的點(例如醫(yī)療機構(gòu)的紅十字),還有線的寬度,在轉(zhuǎn)換到SHP后就沒有了。因而顯示出來的地圖沒有在MapX中顯示的好看,當然可以通過其他方法來顯示這些信息,不過就比較麻煩了,如果用戶對GIS系統(tǒng)的要求比較高的化,用MapWinGIS可能就會有一些麻煩。 在下了MapWinGIS的源碼后我用VS2005編譯了一下,發(fā)現(xiàn)無法通過編譯;用VS2003,在Debug版本下連接出現(xiàn)錯誤,Release版本則編譯通過了,具體什么原因,有時間還要好好琢磨一下 |
|