OGC之路(1) 之 WMS标准学习总结
一切都源于一年多以前,記得是512之后的不久,老板從國外找來一家專門提供地圖業務的公司。他們本來使用ArcGIS作為服務平臺,但是后來考慮到每年昂貴的服務費用,決定把業務拿到中國來,結果就找到我們。其實我們連GIS應用的開發經驗都沒有,不知道老板怎么說的(不愧是老板,要是我只能老老實實說沒做過愿意學)把這個活拿到了手。我得簡單介紹下我們要做的事情。我們需要維護一套C#的代碼(甲方在沿海先找了家公司開發的,然而還是由于維護費用問題又把代碼交給我們)。這套代碼實話說,基本思想是正確的,可惜沒有堅持到底,結果到處都是復制修改的內容。OO的基本原則它幾乎都破壞了完了,可以說是反面教材的典范。但是它的關于GIS的開發是正確的,而且居然還是根據OGC的簡單對象訪問協議進行的設計。我的幾乎所有GIS啟蒙就是對這套代碼的理解。也就是在這里第一次見到了OGC。經過一年焦頭爛額的維護之后,我逐漸深入到GIS的一些底層領域,同時項目組來了新人,我的時間也就富裕了。于是我開始潛心學習OGC的各種標準,首先是通讀,了解OGC的體系結構。然后確定了WMS,WFS,WCS,SLD,Filter,GML為重點學習目標。之所以寫著個系列文章,主要是為了交流,同時也為自己的學習留下記錄。這里給出OGC的連接。
先從一個例子開始,啟動GeoServer,打開瀏覽器,在地址欄敲入如下連接:http://localhost:8080/geoserver/wms?bbox=-130,24,-66,50&styles=population&Format=image/png&request=GetMap&layers=topp:states&width=550&height=250&srs=EPSG:4326,你會看到瀏覽器顯示的美國行政區劃圖(由此美國人的文化勢力可見一斑,不管愿意不愿意,你時不時都會看到他們的國旗,地圖,總統還有總統夫人)。關于上面連接的具體含義,我們會在下面介紹。
再敲入第二個連接:http://localhost:8080/geoserver/wms?service=WMS&request=GetCapabilities,瀏覽器會返回提示打開或保存一個文件,我的機器返回的是一個叫“wms”的文件,沒有擴展名。沒關系我們把它保存為“wms.xml”就可以了。然后用瀏覽器打開,會看到是個相當大的文件,具體內容也會在下面解釋。
這里需要對WMS的調用連接做一個概要介紹,首先我們必須告訴服務器我們想使用WMS服務,因為服務器同時可能還提供了許多其他OGC服務,于是我們設置參數service=WMS。然后我們需要告訴服務器我們想要調用GetCapabilities方法,于是我們設置參數request=GetCapabilities。每個方法可能還有方法的參數,這個就在介紹方法時再說了。到這里我們已經完整的使用了一個WMS服務器的最重要功能,很簡單吧。WMS之所以強大,正是由于它的簡單。“簡單即美”是一切設計的宗旨。
GetCapabilities,如果你想使用一個WMS服務器,那你應該最先調用這個方法。
調用:http://localhost:8080/geoserver/ows?service=WMS&request=GetCapabilities,這個方法返回服務器的能力。一般會是一個很大的XML文檔,關于這個文檔標準有很詳細的描述,這里只做一個提綱式的介紹。
把這個文檔去頭去尾以后留下兩個節點Service和Capability。 Service包含了有關服務器的一般特性數據,對于只是想直接使用WMS服務器的人來說,這個節點還不太用得上,唯一值得注意的就是KeywordList節點,它里面是關鍵字,也就是服務器的保留字。 Capability才是我們學習的重點。如果你想正確的使用WMS服務器,這個節點里面的內容就必須搞清楚了。你可以從這個節點獲得如下信息。
1)服務器支持哪些方法,WMS服務器必須支持GetCapabilities和GetMap,此外還有許多擴展的方法,例如:DescribeLayer以及支持SLD服務器的特殊方法,由于GeoServer不是SLD服務器,這里也就沒辦法了解了。
2)服務器支持哪些返回格式,WMS返回的地圖都是渲染好的圖片,因此這里的格式基本上都是圖片格式(還是有例外不過不在這里介紹了),如:image/png。
3)服務器發布了哪些圖層,這個是WMS的重點,不然你連最簡單的GetMap調用都構造不出來。
下面我們就來學習如何獲得這些數據。首先展開Capability節點,可以看到Request和Layer兩個節點,此外還會有Exception和UserDefinedSymbolization,不過目前對我們用處不大。Request節點包含服務器支持的方法,我這里返回是這樣幾個節點:GetCapabilities,GetMap,GetFeatureInfo,DescribeLayer和GetLegendGraphic(注意老版本的WMS返在這里返回的節點名稱會不一樣,可能會去掉“Get”,我們這里介紹的是1.1.1版本的)。我們只介紹GetCapabilities和GetMap。
先來說說GetCapabilities節點。你也許會說“GetCapabilities”,不就是我們正在討論的方法嗎,是的就是這個方法,你必須調用了這個方法才能知道關于它的特性,很有矛盾吧 :)。在這個節點里面你可以看到Format和DCPType節點,前者指出函數返回內容的格式,其實就是我們正在討論的XML,后者暫時不討論。
GetMap節點的內容同樣也是Format和DCPType節點,這里的Format列出了服務器支持返回的地圖格式。
WMS返回的圖層是嵌套的形式,根節點就是我們將要說到的Layer節點。它里面除了自身的特性外還會包含其他Layer。先來說說Layer自身的特性。先得說明一下,由于Layer存在父子關系,所以他們的特性也就存在繼承關系,子節點支持父節點的特性,而父節點比一定支持子節點的特性。與現實世界一樣,“老子的就是兒子的,兒子的未必是老子的”。
Layer最重要的特性就是Name,在請求方法GetMap的Layers參數中引用的就是這個值,關于GetMap方法的細節后面介紹。然后次重要的特性節點分別是SRS,LatLonBoundingBox,BoundingBox和Style,這些都是出現在GetMap方法中的參數。
需要說明的是,根結點的Layer沒有Name,因為這個Layer只是一個包裝,它里面的“瓤”才是我們感興趣的。而服務器支持的SRS(地理坐標系統)也會在這里來個總匯。這將是一個很長的清單。LatLonBoundingBox是經緯度表示的圖層范圍,依次是minx,miny,maxx,maxy。例如:<LatLonBoundingBox minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0" />。 BoundingBox是圖層默認坐標系表示的范圍與LatLonBoundingBox格式一樣只是多了一個SRS屬性,例如:<BoundingBox SRS="EPSG:26713" minx="588926.6865343997" miny="4913890.332215005" maxx="609271.2114429093" maxy="4927102.448786693" />。Style節點很重要,他表示圖層支持的渲染樣式,就是畫風。一個圖層可以支持多個Style。Style的子節點最重要的就是Name,我們會在GetMap方法的參數Styles中用到。到此為止,Layer節點就介紹完了。
GetMap,如果你想使用一個WMS服務器,那你肯定會不斷調用這個方法。調用:http://localhost:8080/geoserver/wms?request=GetMap&bbox=-130,24,-66,50&srs=EPSG:4326&layers=topp:states&styles=population&Format=image/png&width=550&height=250。
我們有必要詳細說明一下調用參數。前面已經介紹過service和request了,這里集中在GetMap自己的參數上。如果你要調用GetMap方法,無疑要設置request=GetMap。隨后我們需要告訴服務器我們希望看到哪個范圍內的地圖,于是我們設置bbox=-130,24,-66,50,這個bbox使用了EPSG:4326坐標系,于是我們設置srs=EPSG:4326。
我們說過,服務器發布了許多圖層,我們需要指明我們想看的圖層,于是我們設置layers=topp:states,注意layers可以設置多個圖層,用“,”隔開,圖層的渲染順序就是參數設置的順序。我們可以使用默認的樣式來渲染圖層,于是設置styles=,也可以指定渲染樣式,于是設置styles=population。對應layers的設置順序,styles也可以設置多個樣式,用“,”隔開。我們希望返回的圖片是png格式的,于是設置Format=image/png。最后,我們需要告訴服務器,返回的圖片的大小,width=550&height=250,以像素為單位。
到此為止我們介紹完了WMS的調用,其實還有很多內容,想要深入學習的朋友可以去OGC的網站下載完整的文本,PDF格式的。找一些已經實現的開源WMS客戶端通過代碼學習。當然,最有效的學習途徑就是自己實現一個WMS客戶端。下面我們就來實現一個C#版本的WMS瀏覽器。
WmsBrowser需求
1、用戶輸入WMS服務器的URI,點擊一個按鈕調用GetCapabilities方法。然后用返回的數據初始化控制界面。 用戶在控制界面上可以查看服務器的各種Capability數據,并且可以選擇要顯示的圖層,調整圖層順序 ,為圖層設置參數,然后返回一個地圖圖片顯示在預覽區。
2、用戶可以把返回的圖片保存成文件。
已經有許多支持WMS的客戶端了,有許多代碼可供學習和使用。但是,為了不干擾視線,為了避免介紹多余的內容,為了體現“自主創新精神”,最重要的是為了體驗編程的樂趣(這也是我當初進入這個行業的原因),我決定只使用NotNet標準庫提供的類完全從頭開始編寫代碼。
WmsBrowser設計
根據需求,這是一個WinForm的執行程序。需求其實很不明確,完全沒有說明最重要的部分,控制界面,是什么樣子的,用戶如何使用它。所以有必要補充一下了。
控制界面有兩個功能:
1)查看GetCapabilities返回的數據;
2)設置GetMap需要的調用參數。
我們可以據此來設計這個界面。GetCapabilities返回的數據我們前面已經介紹過了,想象一下我們這款軟件的潛在用戶可能想要看到哪些數據,他們會如何使用這些數據。首先肯定是服務器發布的圖層,這是訪問WMS的唯一原因。至于服務器支持哪些調用應該不是他們關心的,而是我們開發者關心的。所以我們需要在界面上顯示出Layer的內容,由于Layer是嵌套的,自然而然我們需要一個樹控件。
除了Layer的Name,Title,Abstract。這些屬性外,用戶應該還需要知道Layer支持的SRS,Style,Format和BoundingBox。這樣他們才能構造出合理的調用參數。我們顯然不應該讓用戶查看完數據后手動構造調用參數,我們需要讓用戶很方便的用鼠標完成工作。我們已經知道需要一個樹控件來顯示Layer信息。然后我們需要提供構造調用參數的界面。首先我們設想用戶可能會如何完成這個工作。
上面的介紹中我們一直是手動敲入字符串來完成調用URI的構建的,繁瑣而且容易出錯,但是這種方法很靈活,所以應該保留。于是我們需要一個TexBox來輸入URI。然后我們需要一個按鈕來發出GetMap請求。我們必須考慮到,有相當一部分人并不善于鍵盤操作(其中包括我),所以我們應該給他們提供鼠標操作模式。于是第二個界面出現了,用戶在這里使用鼠標選擇想要顯示的Layer,調整Layer顯示的順序,選擇每個Layer的Style,選擇Format,選擇SRS,輸入BoundingBox,輸入返回圖片的尺寸。然后同樣點擊上面提到的按鈕,發出GetMap請求。更進一步,我們可以用上面的界面來獲得一個基本的調用參數,然后到TextBox里面去微調,這樣用戶會獲得更好的靈活性。
好了,到這里我們基本上搞清楚控制界面的樣子了。現在需要討論一點設計風格方面的問題。我們可以把所有代碼寫進一個叫MainForm的類里面,它是一個WinForm類。這樣沒有錯,完全可以工作,實際上我見過的大部分代碼都是這么干得。這樣做的結果是,我很快就會放棄這個項目,轉而去瀏覽cnblog或ifeng上面的帖子。我們需要一個更好的設計。我們在這里并不是要討論架構,模式和開發方法,所以我們只需要達成一個共識就可以了:我們需要把界面元素,操作響應以及數據模型分開編碼,為他們單獨建立類體系。
據此我們的設計也就差不多了,開始編碼咯。
WmsBrowser編碼ing。。。
程序完成。
代碼下載
啟動程序后會看見主界面如下:下圖是返回的地圖
?
這個程序還很稚嫩,有許多問題沒有考慮,例如:輸入驗證,數據驗證,異常處理等。以后我們會逐步完善它,目前作為一個參考和學習WMS的起點已經足夠了。
后續
在使用這個程序時,作為用戶,我覺得還有很多不方便的地方。
首先,我如果敲錯了地址,我很容易敲錯,程序會彈出一個丑陋的異常對話框,顯示一大堆堆棧信息,完全看不出是什么錯誤。
其次,設置參數BBox很不方便,如果能從已有的地圖上用鼠標選擇就好了。
還有,返回時只是顯示一個圖片想看細節又要重復設置,Apply,GetMap的操作,太繁瑣了。
以上就是我作為用戶對這款軟件的看法,看來我們急需改進。我們會在以后的討論中逐步完善這個程序。
轉載于:https://www.cnblogs.com/sillyemperor/archive/2009/09/27/1575170.html
總結
以上是生活随笔為你收集整理的OGC之路(1) 之 WMS标准学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET自定义多文件(图片)上传的实现方
- 下一篇: 找不到using System.Web.