標籤:blog http os 使用 sp 資料 2014 問題 log
1.背景
在上一章裡講解地圖平移功能的實現時,我在最後提出了兩個問題:
A.在地圖平移後,向量圖層的canvas的XY都發生了變化,此時根據地理座標轉換為螢幕座標公式得出的螢幕座標,在canvas上能將要素正確顯示嗎?
B.向量圖層canvas的原點座標XY有需要還原成初始的(0,0)的時候嗎?
對這兩個問題我給出的答案是:不能和需要。
在這一章裡,我們將詳細講解得出這兩個答案的原因。
2.何為位移補償量?
在地圖平移時,我們做了兩個操作:一個是對MapCanvas的原點座標XY進行了變化,第二個是對此時螢幕的實際地理範圍做了變化。詳細的實現過程以及公式可以參考上一章WebGIS中平移功能的設計和實現。
而這兩個操作都需要用到一個共同的參數,即此時操作位移量(moveX,moveY)。但是,此時操作位移量並不是位移補償量。位移補償量,是針對於初始座標(0,0),此時canvas的左上方座標XY的整體位移量,我們用做(sumMoveX,sumMoveY)來表示。
3.位移補償量的影響3.1如果不考慮位移補償量,會出現的問題
假設,此時地圖的canvas原點已經被平移了(sumMoveX,sumMoveY),當我們再次使用地理或商務服務端的向量服務,解析返回的向量資料中的Geometry時,會先把Geometry中的地理座標轉換螢幕座標,然後再將此時用螢幕座標繪出的要素添加到該canvas中。但是,問題來了,我們會發現,此時的要素並不在我們想要的位置上(實際座標處),而是在了其他地方從而發生了位移。這也是我們第一個問題的完整描述。
3.2出現此問題的原因3.2.1 回顧螢幕座標與地理座標互轉換公式
在討論此問題前,我們有必要回看一下我在第十章中給出的螢幕座標和地理座標互轉換的公式:
A.螢幕座標轉換為地理座標
geoXY.x = screenGeoBounds.left + screenX * sliceLevelLength / tileSize;
geoXY.y = screenGeoBounds.top - screenY * sliceLevelLength / tileSize;
B.地理座標轉換為螢幕座標
screenXY.x = (geoX - screenGeoBounds.left)/(sliceLevelLength/ tileSize);
screenXY.y = (screenGeoBounds.top - geoY)/(sliceLevelLength/ tileSize);
其中geoXY表示地理座標,screenXY表示螢幕座標,screenGeoBounds表示螢幕地理範圍,slieceLevelLenth表示此事地圖層級下的一張瓦片所代表的實際地理長度,tileSize表示一張瓦片的像素大小。
3.2.2 從公式分析產生位移的問題
我們仔細觀察地理座標轉換為螢幕座標的公式,其原理是,用此時的地理座標減去螢幕容器左上方所代表的地理座標,然後除以一個像素所代表的地理長度,得出此時相對於螢幕容器左上方座標的螢幕座標。
大家看我的描述中,反覆提到的是螢幕容器左上方座標,何為螢幕容器左上方座標呢?我們再看下上一章我給出的平移原理:
這其中的容器左上方螢幕座標就是初始時和canvas左上方A點重疊的座標(0,0)。
所以,當我們把一個相對於(0,0)的要素,加入到一個左上方已經變為(sumMoveX,sumMoveY)的canvas中時,便發生了要素位置位移的問題。
3.3如何解決此位移問題
知道了引發位移的問題,我們便只需要對症下藥即可。即當我們把向量資料中的地理座標變為螢幕座標後,再減去一個位移補償量即可。
也就是:
ScreenXY=geoXYToSreenXY(geoXY)-sumMoveXY
表現在代碼層面上,便是繪製時,將轉換得到的螢幕座標減去位移補償量。
4.位移補償量何時歸零?
要弄清楚這個問題,我們得再次研究座標轉換公式。在這個公式中涉及到一個重要的參數,即sliceLevelLength,當前地圖層級下瓦片長度所代表的實際地理長度。
試想,當我們的地圖層級變化了,則此參數sliceLevelLength也變化了,如果sumMoveXY還是之前的那個數字,那麼sumMoveXY所代表 實際地理長度便不再是正確的地理長度了。
這樣會導致一個問題,地圖層級變化後,如果繼續使用之前的sumMoveXY值,得到的轉換後的螢幕座標會發生位移。
此時,我們如果採用這樣一種做法,在地圖層級變化後,將所有的sumMoveXY都變成0,即重新恢複到未發生位移的狀態下,則能很好的解決如果保留sumMoveXY值所引發的位置位移問題。
表現在代碼層面上,便是每次地圖進行層級變化時,會拋出一個zoom事件,圖層應該監聽此事件,然後將圖層(canvas)的做上角座標XY變為0。
5.進一步探討位移補償量本質以及其引發的問題5.1 提出問題
這裡,我繼續給出兩個問題:
A.本希望每次點擊滑鼠後能在滑鼠點擊的地方畫出一個圓點,可是當拖動了地圖後,滑鼠再點擊到地圖上時,卻沒有將圓點畫在點擊的地方,而是位移了。
B.同樣也是想點擊滑鼠後能在滑鼠點擊的地方畫出一個圓點,即使不拖動地圖,當滑鼠點擊到已經畫出的要素上後,發現現在畫出的圓點位移到其他地方了。
5.2實驗及實驗結果分析
在解答上面兩個問題時,我首先給出一組實驗資料。
stageXY:全域舞台的座標;
localXY: 本地座標系;
geoPoint:此時的地理座標;
mapDrawCanvas:此圖層(Canvas)的原點座標;
screenPoint:此時將地理座標轉換為螢幕座標後的座標;
fixedSreenPoint:將screenPoint減去位移量後的修正座標;
1)未拖動地圖時,即沒有位移補償量時:
2)拖動地圖後,即有位移補償量時:
5.2.1結論1—用於座標轉換的螢幕座標最好是stageXY
在不拖動地圖和拖動地圖的情況下,stageXY和將地理座標轉換成螢幕座標後的screenPoint是能很好的對應的。其原因,我們在仔細的看了地理座標轉換成螢幕座標的公式後就不難理解了,因為轉換回來的螢幕座標其相對的是(0,0)座標,而此mapDrawCanvas所對應的stageXY座標便是相對於(0,0)的。
這個結論告訴我們,用於座標轉換的螢幕座標最好是stageXY。
5.2.2 結論2-轉換得到的螢幕座標必須減去位移量後才能等於此時的localXY
觀察實驗結論,將screenPoint減去位移量後得到的fixedScreenPoint去掉最小誤差便是等於localXY。而想要在一個容器內畫圖,必須是使用其localXY座標。
5.2.3 結論3-位移量便是容器的原點(mapDrawCanvas .x, mapDrawCanvas .y)
我們發現,當容器(mapDrawCanvas)的原點座標(mapDrawCanvas .x, mapDrawCanvas .y)變化後,在本地座標系下所得的localXY也發生了相關的變化。而這個位移量,便可以直接使用容器的原點。
5.3 問題解答
由結論1我們可以知道,用於座標轉換的座標最好是stageXY。
問題1的原因在於,使用localXY作為螢幕座標,然後將localXY轉換成地理座標後進行儲存。在地圖平移後,此時儲存的地理座標便不再是正確的地理座標了,於是要素繪製時發生了位移。
問題2的原因在於,當我們點擊到一個要素後,此時獲得的localXY不再是相對於容器mapDrawCanvas的本地座標了,而是相對於該被點擊要素的本地座標。所以座標轉換後會出現很嚴重的位移。
6.總結
在這一章裡,我們詳細對位移補償量的本質及其造成的問題和解決方案。在這一章裡,我們提到了很多之前已經講到的內容,主要包括座標轉換以及平移本質。最後我給出了一個簡單的實驗資料,為大家進一步講解了位移補償量的本質。
在下一章裡,我們將跟大家一起討論工具條中長度量算工具和面積量算工具所涉及的演算法、設計和實現。希望大家持續關注。
--------歡迎轉載,但保留著作權,請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/
(十六)WebGIS中位移補償量引發的問題之探討