WebGIS
設計與實現原理
褫其華袞,示人本相系列之一2006-2-18cheungmine1 什麼是WebGIS 我的定義是:在internet領域內,向WWW伺服器請求地圖資料或與之相關的操作,從而獲得地圖並呈現給終端使用者的過程。幾點共識是:用戶端不必安裝任何外掛程式(當然必要的瀏覽器和XML支援是少不了的);服務端動態產生地圖(強調這一點,是因為這樣的Webgis引擎才符合工業標準。否則只能稱為帶有地圖圖片的網站)。符合上述定義的Webgis的優點是顯而易見的:(1)地圖由伺服器動態按需產生,發送給用戶端只是最終產生的圖片(我的經驗是png格式為好),對用戶端的要求降到最低。(2)利用伺服器的中心控制、監視和審計,保障了資料的安全和實現的一致性。(3)方便部署的特徵,使升級和擴充都異常簡單。因此,我希望以後在談論Webgis的時候,再也不要聽到Plugin、ActiveX、Applet之類的字眼。 2 Webgis技術原理 說了一大堆,就要談到核心實現了。別以為我在這裡胡吹海侃,我確實是真的把自己的體會和經驗(教訓)無償的奉獻給莘莘學子。我的體會是:(1)一種技術,如果太過複雜,就稱不上是好技術。比如質能方程E=MC*C其簡單和優美。所以,我以為宇宙的定律就是簡單的規則,當然,多數我們還沒發現。(2)一種實現,如果要寫一大堆的代碼,仍然不是一種好的實現。就比如誇一個人長的美,說一千道一萬,不如就2個字:好看。秉承這個原則,下面介紹我的技術:(1)用戶端(IE)採用AJAX,直接調用服務端的Services。(2)服務端編寫Web Services,響應客戶的請求。原理就這些,為什麼我就不說了,如果你不知道,說明你還需要學啊學啊學。 3 Webgis實現 先說服務端的實現。按上面說的,就是寫Web Services(Web服務)。可能目前沒有比寫Web Services更時髦的了。還有人說Google Web API要代替傳統的Win32API。其實這完全是2種計算模式,誰也代替不了誰。許多專家就喜歡炒作,把媒體那一套應用到我們這個技術領域,誤導消費者。 其實,若不是瀏覽器大行其道,Webgis算個啥啊。這社會從來就沒公平過,好好的C/S不用,非強迫我們在瀏覽器裡搞啊搞的。沒辦法,就搞吧,看誰搞得過誰? 寫Web Services有很多語言可寫,什麼C#、Java、C++等等等等。需要一套稱之為Webgis API的東西。設計這樣一套API讓AJAX調用。怎麼設計呢,我會把我的介面公布出來,供大家參考漫罵。 其實最重要的是服務端的地圖產生引擎(引擎就是發動機)。我自己實現了一個(帶VVT-i的啊),沒有的要自己實現,或者買個現成的(比如MapObjects)。 該說用戶端了。AJAX嗎,其實就是JavaScript + XMLHttpRequest(微軟版本)對象啊。就別用什麼Webservices.htc了,雖然是微軟寫的,還真他媽不好用。我從高人那裡抄了一個,改了改,就用上了。看我上篇文章啊,那個是100%的原始碼,沒錯誤的啊。 剩下的再說就顯得多餘了。畫個體繫結構圖吧: (圖象怎麼顯示不出來??) WebGIS體繫結構圖 4 小貼示 看到這裡你是不是覺得噁心了,提示就提示幹嘛貼示啊。不是有國內北大高人翻譯《ATL 技術內幕》非滿紙的“控制”。我看了就彆扭,國內叫“控制項”,這個還比較舒服。翻譯的就別提多牽強了。(1)服務端要以多線程(IIS進程)服務要求。(2)地圖引擎載入資料,要能夠靜態和動態2種模式載入。(3)絕對不要想著傳向量的資料,傳圖片最好,哪怕未來網路頻寬提高100倍。(4)寫的要絕對健壯,不然把IIS搞癱了。(5)記得在服務端保持客戶狀態啊。 5 附錄:Webgis WebServices 介面和方法也許一不小心成了標準呢?其實就是想讓讀者在做這方面的設計時,有個參考,反面典型也好。我把修改資料方面的API去掉了,太危險了,還是不說出來的好。 // Webgis介面方法說明// 2006年8月// ATL Server Webgis Services Created by cheungmine@gmail.com//////////////////////////////////////////////////////// 關於MtkWebgisService//////////////////////////////////////////////////////// 取得服務相關資訊HRESULT about([out, retval] BSTR *Info); // 取得伺服器日期時間HRESULT svrtime([out, retval] mtkTime *time); //////////////////////////////////////////////////////// 登入與登出, login必須是第1個調用的服務端方法//////////////////////////////////////////////////////// 登入系統, 獲得使用者令牌和全圖URL, 以後任何方法調用必須給出令牌HRESULT login([in] BSTR Username, [in] BSTR Password); // 登出系統, 登出使用者令牌HRESULT logout(); //////////////////////////////////////////////////////// 基本資料//////////////////////////////////////////////////////// 當前MTK Canvas版本HRESULT version([out, retval] BSTR *Ver); // 取得全部圖層資訊, 以XML內聯返回HRESULT mapinfo([out, retval] BSTR *xmlInfo); // 取得全部圖層資訊, 返回產生的XML的URLHRESULT mapxml([out, retval] BSTR *xmlURL); // 取得圖層資訊, 以XML內聯返回HRESULT layinfo([in] LONG LayerIndex, [out, retval] BSTR *xmlInfo); // 取得圖形屬性資訊, 以XML內聯返回. 若圖層索引為>=MTK_TMPLAYER_INDEX, 則在臨時層上HRESULT shpinfo([in] LONG LayerIndex, [in] LONG fromShapeIndex, [in] LONG fetchCount, [out, retval] BSTR *xmlInfo); // 取得圖形屬性資訊, 返回產生的XML的URL. 若圖層索引為>=MTK_TMPLAYER_INDEX, 則在臨時層上HRESULT shpxml([in] LONG LayerIndex, [in] LONG fromShapeIndex, [in] LONG fetchCount, [out, retval] BSTR *xmlURL); //////////////////////////////////////////////////////// 地圖瀏覽和點查//////////////////////////////////////////////////////// 重新整理地圖, 取地圖imgURLHRESULT refresh([out] DOUBLE* Scale, [out, retval] BSTR *imgURL); // 地圖控制顯示比例HRESULT scale([out] DOUBLE* minScale, [out] DOUBLE* maxScale); // 按比例顯示地圖, 不改變當前地圖中心位置HRESULT zoom([in] DOUBLE Scale); // 指定視圖位置放大或縮小地圖, 指定放大縮小的百分比HRESULT zoomat([in] mtkPoint Pos, [in] SHORT Percent); // 開窗顯示地圖, 指定視圖上的2點HRESULT zoomext([in] mtkPoint Pos1, [in] mtkPoint Pos2);// 開窗顯示地圖, 指定地圖上的2點HRESULT zoomext2([in] mtkPoint Pt1, [in] mtkPoint Pt2); // 移動地圖, 指定視圖上的2點HRESULT move([in] mtkPoint fromPos, [in] mtkPoint toPos); // 選中繪圖物件, 指定視圖上的點. 返回對象的sid負值和所在的圖層索引和對象資訊HRESULT identify([in] mtkPoint Pos, [out] LONG* _sid, [out] LONG* layId, [out, retval] BSTR* shpInfo); // 設定圖層狀態屬性, 指定層的索引和狀態名稱, 狀態值HRESULT setlayer([in] LONG LayerIndex, [in] mtkEnumLayerState State, [in] bool bVal); // 以指定視圖上的點為中心, 定位地圖HRESULT centerat([in] mtkPoint Pos); // 以指定地圖座標點為中心, 定位地圖HRESULT centerat2([in] mtkPoint Pt); // 地圖翻頁, 指定方向Up,Down,Right,Left和頁面重疊百分率0%~100%"HRESULT flip([in] mtkEnumFlip Direction, [in] SHORT Overlap); // 清除選中的對象HRESULT clear(); //////////////////////////////////////////////////////// 地圖測量, 視圖上的點串//////////////////////////////////////////////////////// 地圖測量, 返回距離, 面積和地圖單位HRESULT measure([in] mtkPoints PathPoints, [out] DOUBLE* Length, [out] DOUBLE* Area, [out] BSTR* Unit); // 地圖測量, 返回距離, 面積和地圖單位HRESULT measure2([in] BSTR PathString, [out] DOUBLE* Length, [out] DOUBLE* Area, [out] BSTR* Unit); //////////////////////////////////////////////////////// 座標變換: 視圖(view)與資料(data)之間的正反座標變換//////////////////////////////////////////////////////// 取得地圖當前資料座標範圍HRESULT extent([out] DOUBLE* MinX, [out] DOUBLE* MinY, [out] DOUBLE* MaxX, [out] DOUBLE* MaxY); // 視圖點變換到資料座標點HRESULT vp2dp([in] LONG VX, [in] LONG VY, [out] DOUBLE* DX, [out] DOUBLE* DY); // 資料座標點變換到視圖點HRESULT dp2vp([in] DOUBLE DX, [in] DOUBLE DY, [out] LONG* VX, [out] LONG* VY); // 視圖點串變換到資料座標點串HRESULT vs2ds([in] BSTR VS, [out, retval] BSTR* DS); // 資料座標點串變換到視圖點串HRESULT ds2vs([in] BSTR DS, [out, retval] BSTR* VS); //////////////////////////////////////////////////////// 空間查詢與分析//////////////////////////////////////////////////////// 重設過濾器. 清除所有以前設定的過濾器HRESULT resetFilters(); // 設定過濾器, 可以多次調用此方法以設定多個過濾器, 只要服務端支援多過濾. 返回過濾器總數HRESULT addFilter([in] mtkFilter Filter, [out, retval] LONG* Count); // 根據條件尋找繪圖物件, 返回查詢到的對象數. 查詢結果圖層為臨時層, 索引為i+MTK_TMPLAYER_INDEXHRESULT findShapes([in] LONG LayerIndex, [in] BSTR SqlClause, [in] bool UseFilters, [out, retval] LONG* Count); // 產生緩衝區圖形, 返回靶心圖表形sid. 此操作都在跟蹤層中HRESULT bufferShape([in] LONG sid, [in] DOUBLE Distance, [out, retval] LONG* sidDst); // 將非跟蹤層中的圖形資料儲存到跟蹤層中, 返回圖形sidHRESULT trackShape([in] LONG LayerIndex, [in] LONG ShapeIndex, [out, retval] LONG* sid); //////////////////////////////////////////////////////// 圖形編輯//////////////////////////////////////////////////////// 建立新繪圖物件, 返回繪圖物件的IDHRESULT createShape([in] mtkEnumGeometry GType, [out, retval] LONG* sid); // 向新繪圖物件中增加視圖上的點, 象素座標HRESULT addPt([in] LONG sid, [in] mtkPoint Pos); // 向新繪圖物件中增加點, 地圖座標HRESULT addPt2([in] LONG sid, [in] mtkPoint Pt); // 向繪圖物件中增加單一屬性, 指明列索引0-based, 列值HRESULT setCol([in] LONG sid, [in] SHORT colId, [in] BSTR colVal); // 清除指定sid的圖形. 繪製的圖形都儲存在跟蹤層中. sid=0全部刪除HRESULT clearShape([in] LONG sid);