GIS地圖開發(fā) - 全文
一、 地圖是怎么做出來的
首先說一下地圖是怎么出來的,可能你感覺是廢話,但實(shí)際上很多人并不知道如何下手。我覺得這里需要先給你個(gè)思路準(zhǔn)備:地圖就是使用繪圖語句畫出來的!
從底層繪制地圖,能使用的就是繪圖函數(shù),在.NET里,就是用Graphics類的方法,在窗口中繪制點(diǎn)、線、面、標(biāo)準(zhǔn)、柵格等,組合起來,就是一張地圖(瓦片圖方式除外)。
關(guān)于.NET的繪圖,本文不進(jìn)行講解,如果你還還不熟悉,建議你先看看這方面資料。
二、 坐標(biāo)轉(zhuǎn)換-地圖繪制的關(guān)鍵
.NET提供了大量繪圖方法,基本上都是以Graphics類的函數(shù)形式提供,包括各類幾何形狀、圖像、文字的繪制,靈活運(yùn)用這些方法,就可以畫出精美的圖出來。假設(shè)你已熟悉.NET的繪圖,這樣就只有有一個(gè)問題要解決:圖我會(huì)畫了,但拿到地圖元素一般為地理坐標(biāo)(經(jīng)緯度),應(yīng)該畫在地圖上什么位置?這就需要涉及到坐標(biāo)轉(zhuǎn)換問題。
先不考慮怎么實(shí)現(xiàn),首先需要這么一個(gè)函數(shù):
/// 《summary》
/// 經(jīng)緯度轉(zhuǎn)換為屏幕坐標(biāo)
/// 《/summary》
/// 《param name=“xy”》經(jīng)緯度《/param》
/// 《returns》屏幕坐標(biāo)《/returns》
public Point WorldToScreen(PointF xy)
再一個(gè),有時(shí),還需要根據(jù)屏幕上點(diǎn)位置反算出它的經(jīng)緯度,如在需要顯示鼠標(biāo)指針處的經(jīng)緯度,所以還需要這么一個(gè)函數(shù):
/// 《summary》
/// 屏幕坐標(biāo)轉(zhuǎn)換為經(jīng)緯度
/// 《/summary》
/// 《param name=“xy”》屏幕坐標(biāo)《/param》
/// 《returns》經(jīng)緯度《/returns》
public PointF ScreenToWorld(Point xy)
有了這兩個(gè)函數(shù),就可以將以經(jīng)緯度表示的地理坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo),然后再屏幕繪圖了。
為了完成坐標(biāo)轉(zhuǎn)換,需要使用幾個(gè)地圖參數(shù)的變量:地圖縮放倍數(shù)、地圖中心點(diǎn)經(jīng)緯度、地圖大小,關(guān)于地圖參數(shù),可參考這篇文章:
http://hi.baidu.com/geochenyj/blog/item/6b5c5c1294057557f819b835.html
另外,還需要對(duì)地圖進(jìn)行縮放、平移,這些操作實(shí)質(zhì)上也是對(duì)地圖參數(shù)的操作,如放大就是對(duì)地圖縮放倍數(shù)操作,平移就是對(duì)地圖中心點(diǎn)進(jìn)行操作,我們將這些操作也寫Coordinator類的方法。投影變換也作為坐標(biāo)轉(zhuǎn)換的一部分,Coordinator類還增加了投影方面方法,這個(gè)后面再講。
將上面兩個(gè)坐標(biāo)轉(zhuǎn)換函數(shù)和三個(gè)地圖參數(shù)封裝為一個(gè)類Coordinator。,的類如下所示:
?
三、 繪圖
有了坐標(biāo)轉(zhuǎn)換類Coordinator,就可以用經(jīng)緯度數(shù)據(jù)來繪圖了,如拿到某省的行政邊界經(jīng)緯度坐標(biāo)數(shù)據(jù),就可以將經(jīng)緯度數(shù)據(jù)轉(zhuǎn)換為屏幕坐標(biāo),然后用Graphics的方法來畫出來了,Graphics對(duì)象又從哪里來呢?可以從一個(gè)Image對(duì)象創(chuàng)建,也可以從一個(gè)控件的Paint事件中取得,總之,有了坐標(biāo),發(fā)揮你的想象力,自己畫吧。
在氣象數(shù)據(jù)分析中,除了要繪制點(diǎn)、線、面、文字、柵格外,還需要繪制一些特殊符號(hào),如風(fēng)、天氣現(xiàn)象、云等。這些符號(hào),可以用圖片、天氣字庫、符號(hào)庫來實(shí)現(xiàn),圖片方式實(shí)現(xiàn)簡(jiǎn)單,色彩豐富,但縮放效果不好;字庫方式,需要安裝字庫,程序部署比較麻煩;符號(hào)庫方式代碼編寫較麻煩。FreeMicaps的天氣現(xiàn)象符號(hào)采用符號(hào)庫方式,祥見: http://blog.csdn.net/HZGJF/archive/2009/05/27/4220508.aspx
風(fēng)符號(hào)和云量符號(hào)采用計(jì)算坐標(biāo)繪制方式。
為了使用方便,F(xiàn)reeMicaps把符號(hào)繪制功能封裝到三個(gè)符號(hào)類中,以靜態(tài)方法提供。
?
.NET的繪圖是對(duì)GDI+的封裝,包括了對(duì)點(diǎn)、線、面等各種圖形元素的封裝,圖形圖像的繪制、坐標(biāo)旋轉(zhuǎn),各種反走樣和平滑等功能,功能十分強(qiáng)大(當(dāng)然,效率不太高),利用它可以繪出漂亮的圖形。
根據(jù)OGC標(biāo)準(zhǔn),GIS系統(tǒng)首先需要對(duì)地圖元素進(jìn)行抽象和封裝,但FreeMicaps中,經(jīng)再三考慮,放棄了這種方式,一個(gè)是因?yàn)楣ぷ髁勘容^大,另一個(gè)是因?yàn)槲也桓冶WC能很好地進(jìn)行封裝,可能給插件開發(fā)帶來麻煩,不如把繪圖權(quán)完全交給圖層,大家自由發(fā)揮。
四、 圖層
為了使繪圖過程便于管理,可將繪圖過程分為組,如可以將一張地圖的繪制分為:繪制世界地圖、繪制中國(guó)地圖、繪制河流、填地名幾個(gè)過程,每次繪圖好像就是在一張玻璃上繪制,疊加起來就形成了一張地圖圖,這里把每次繪圖過程形象地稱為一個(gè)圖層。地圖分層后,圖層可以增刪,每個(gè)圖層可以單獨(dú)進(jìn)行隱藏、設(shè)置屬性等,更重要的是可以將利用面向?qū)ο蠹夹g(shù)把每個(gè)圖層當(dāng)做一個(gè)對(duì)象進(jìn)行管理。詳細(xì)介紹見:http://blog.csdn.net/HZGJF/archive/2008/10/03/3014558.aspx
對(duì)圖層進(jìn)行抽象,它應(yīng)該有一個(gè)圖層繪制方法(Render),一個(gè)圖層標(biāo)題(LayerName),一個(gè)用于表示數(shù)據(jù)源的字符串(DataSource),一個(gè)用于表示繪圖樣式的設(shè)置的LayerStyle,加上一些輔助方法屬性,最終形成如下抽象圖層類(CustomLayer),各種圖層均從它繼承:
?
FreeMicaps中,每種數(shù)據(jù)對(duì)應(yīng)一種圖層類,為了使圖層類編寫方便,使用了設(shè)計(jì)模式中的模板方法,定義繪制流程,主程序在調(diào)用圖層的Render()方法時(shí),會(huì)自動(dòng)判斷是否已經(jīng)讀入數(shù)據(jù),根據(jù)需要讀數(shù)據(jù)繪圖。
對(duì)于一種類型數(shù)據(jù),需要從CustomLayer繼承新建一個(gè)圖層類。各種類型數(shù)據(jù)圖層的工作方式完全一樣,僅在數(shù)據(jù)讀取和繪制方面不同,所以,寫新圖層類時(shí),僅需實(shí)現(xiàn)DoLoad()和DoRender()兩個(gè)抽象方法,完成讀取數(shù)據(jù)和繪制圖層代碼即可。FreeMicaps里使用了字符串作為數(shù)據(jù)源標(biāo)識(shí),通用GIS系統(tǒng)對(duì)數(shù)據(jù)源進(jìn)行了抽象,我也嘗試這么做,但代碼過于復(fù)雜,增加圖層開發(fā)難度,最終增大插件開發(fā)難度,所以放棄了。
前面說了,一張地圖有多個(gè)圖層,所以還需要將圖層放入一個(gè)列表,繪制地圖時(shí)遍歷圖層,調(diào)用每個(gè)圖層的Render()方法,畫出一張完整的地圖。對(duì)于圖層列表,大家馬上會(huì)想到使用List類,但圖層繪制是需要有順序的,如在衛(wèi)星云圖上面疊加地名,需要先畫衛(wèi)星云圖,再填地名,否則云圖會(huì)把地名蓋住,所以在圖層的樣式(LayerStyle)中放了一個(gè)ZOrder屬性,通過它來控制圖層順序。但由于List本身的排序方法是一種“非穩(wěn)固排序”,也就是說當(dāng)兩個(gè)圖層的ZOrder相等時(shí),它們的順序是不確定的,為了避免這個(gè)問題,F(xiàn)reeMicaps從CollectionBase繼承了一個(gè)類LayerList,實(shí)現(xiàn)對(duì)圖層的管理,并實(shí)現(xiàn)了IXmlSerializable接口,完成圖層序列化功能。另外,還增加了添加圖層、刪除圖層事件。LayerList類如下:
FreeMicaps中,每種數(shù)據(jù)對(duì)應(yīng)一種圖層類,為了使圖層類編寫方便,使用了設(shè)計(jì)模式中的模板方法,定義繪制流程,主程序在調(diào)用圖層的Render()方法時(shí),會(huì)自動(dòng)判斷是否已經(jīng)讀入數(shù)據(jù),根據(jù)需要讀數(shù)據(jù)繪圖。
對(duì)于一種類型數(shù)據(jù),需要從CustomLayer繼承新建一個(gè)圖層類。各種類型數(shù)據(jù)圖層的工作方式完全一樣,僅在數(shù)據(jù)讀取和繪制方面不同,所以,寫新圖層類時(shí),僅需實(shí)現(xiàn)DoLoad()和DoRender()兩個(gè)抽象方法,完成讀取數(shù)據(jù)和繪制圖層代碼即可。FreeMicaps里使用了字符串作為數(shù)據(jù)源標(biāo)識(shí),通用GIS系統(tǒng)對(duì)數(shù)據(jù)源進(jìn)行了抽象,我也嘗試這么做,但代碼過于復(fù)雜,增加圖層開發(fā)難度,最終增大插件開發(fā)難度,所以放棄了。
前面說了,一張地圖有多個(gè)圖層,所以還需要將圖層放入一個(gè)列表,繪制地圖時(shí)遍歷圖層,調(diào)用每個(gè)圖層的Render()方法,畫出一張完整的地圖。對(duì)于圖層列表,大家馬上會(huì)想到使用List類,但圖層繪制是需要有順序的,如在衛(wèi)星云圖上面疊加地名,需要先畫衛(wèi)星云圖,再填地名,否則云圖會(huì)把地名蓋住,所以在圖層的樣式(LayerStyle)中放了一個(gè)ZOrder屬性,通過它來控制圖層順序。但由于List本身的排序方法是一種“非穩(wěn)固排序”,也就是說當(dāng)兩個(gè)圖層的ZOrder相等時(shí),它們的順序是不確定的,為了避免這個(gè)問題,F(xiàn)reeMicaps從CollectionBase繼承了一個(gè)類LayerList,實(shí)現(xiàn)對(duì)圖層的管理,并實(shí)現(xiàn)了IXmlSerializable接口,完成圖層序列化功能。另外,還增加了添加圖層、刪除圖層事件。?
五、 封裝地圖
有了坐標(biāo)轉(zhuǎn)換類、圖層類、圖層列表類,就可以利用它們做出一個(gè)具有縮放平移、圖層管理等功能的地圖了,但為了更方便地對(duì)地圖進(jìn)行操作,還需要對(duì)這些類進(jìn)行組合封裝。新建一個(gè)類WeatherMap,添加Coordinator和LayerList類的實(shí)例作為它的屬性,為了更符合大家操作習(xí)慣,將Coordinator類的實(shí)例作為私有成員,將地圖坐標(biāo)轉(zhuǎn)換等方法加入WeatherMap類,也就是說地圖坐標(biāo)轉(zhuǎn)換中,不訪問Coordinator,而要調(diào)用WeatherMap類的方法。類圖如下:
?
再回到抽象圖層類CustomLayer,它有一個(gè)成員Map,即為WeatherMap對(duì)象,在將圖層加入圖層列表時(shí)會(huì)自動(dòng)賦值。在編寫CustomLayer的子類時(shí),可調(diào)用它來進(jìn)行坐標(biāo)轉(zhuǎn)換和地圖操作。
為了使地圖在繪制復(fù)雜圖形過程中不至于假死,并在繪圖過程中能隨時(shí)中斷繪圖,如快速縮放平移地圖中可終止前次繪圖過程直接繪制最后一次,地圖繪制使用了多線程,但多線程增加了代碼編寫難度,特別是多線程操作UI,對(duì)程序流程造成了一定混亂,程序結(jié)構(gòu)受到影響,所幸并不會(huì)對(duì)圖層代碼造成困難。
六、 再次封裝-增加UI
上面已完成了地圖繪制的核心代碼,為了使代碼編寫更加容易,需要對(duì)WeatherMap類再次進(jìn)行封裝(MapView類),加入U(xiǎn)I部分,即給地圖加一個(gè)具有界面的殼,并在上面實(shí)現(xiàn)地圖的操作如縮放、拖動(dòng)功能。
MapView從PictureBox類繼承,內(nèi)建了WeatherMap類的實(shí)例,在MapView的Refresh()方法中調(diào)用WeatherMap.Render()對(duì)地圖進(jìn)行繪制。
為了完成對(duì)地圖的操作,F(xiàn)reeMicaps定義一個(gè)IMapTool接口,包含了鼠標(biāo)和鍵盤操作方法,MapView類內(nèi)建一個(gè)IMapTool接口成員,MapView的鼠標(biāo)和鍵盤操作,將被IMapTool接口的實(shí)例接管,在實(shí)現(xiàn)IMapTool接口的類中,可對(duì)地圖做各種操作,如平移、縮放等操作,這個(gè)對(duì)象可隨時(shí)替換以實(shí)現(xiàn)不同方式的地圖操作。在FreeMicaps中,已完成一個(gè)實(shí)現(xiàn)IMapTool接口的類ZoomTool,此類為默認(rèn)的地圖縮放和平移工具。IMapTool接口類圖如下:
?
另外,在MapView中,還引入了一個(gè)當(dāng)前圖層的概念CurrentLayer,用它來表示當(dāng)前操作的圖層,后面用它來實(shí)現(xiàn)圖層元素拾取、圖層工具條等功能。
MapView類圖如下:
?
七、 總覽
地圖部分類關(guān)系圖如下:
?
地圖繪制部分活動(dòng)圖如下:
?
以上已經(jīng)介紹完FreeMicaps地圖部分設(shè)計(jì)框架,相信大家的已對(duì)設(shè)計(jì)思路已有一定了解,此框架不僅適用于天氣圖分析軟件,也適用于一般的GIS系統(tǒng)。本文僅對(duì)FreeMicaps的地圖部分框架進(jìn)行了介紹,未涉及到具體的地圖數(shù)據(jù)讀取及繪制,這些將在下一篇文章中介紹。
- 第 1 頁:GIS地圖開發(fā)
- 第 2 頁:GIS地圖開發(fā)(二)
本文導(dǎo)航
非常好我支持^.^
(0) 0%
不好我反對(duì)
(0) 0%
相關(guān)閱讀:
- [電子說] 中易云GIS場(chǎng)景信息管理平臺(tái)提供強(qiáng)大的空間分析功能 2023-10-21
- [可編程邏輯] 基于FPGA系統(tǒng)Register和Memory的復(fù)位 2023-10-09
- [電子說] GIS組合電器安裝事項(xiàng) 2023-09-26
- [電子說] 潤(rùn)和軟件HopeStage與超圖軟件 GIS平臺(tái)完成產(chǎn)品兼容性互認(rèn)證 2023-09-25
- [電子說] 淺析C語言中的regiseter關(guān)鍵字 2023-08-25
- [電子說] 變電站GIS室內(nèi)六氟化硫氣體泄露報(bào)警監(jiān)測(cè)系統(tǒng)的應(yīng)用方案 2023-08-16
- [電子說] 分布式應(yīng)急指揮中心方案 2023-08-16
- [電子說] 助力GIS配電室氣體減排--六氟化硫SF6氣體在線監(jiān)測(cè)報(bào)警系統(tǒng) 2023-07-19
( 發(fā)表人:彭菁 )