zoukankan      html  css  js  c++  java
  • Google Earth的脫機應用-本地模擬瓦片系統

    Google Earth(一下簡稱GE)的衛片數據均來自Google的服務器,雖然GE使用緩存技術來保存衛片以達到脫機使用的目的,但是GE允許的緩存空間最大只有4G,因此想要利用GE作為類GIS平台並且脫機使用,對於衛片數據來說,GE允許的緩存空間是遠遠不夠的,在擁有衛片數據的基礎上,需要在本地模擬GE瓦片的加載過程,這一需要將通過Google Earth API和KML來實現!

    KML(Keyhole Markup Language)Keyhole標記語言,一種基於XML語法和格式,用於描述和保存地理信息的編碼規範,可以被GE識別並顯示。由KML編寫的文件稱為KML文件,KML允許通過<Icon>標簽使用圖片資源,並且允許<LookAt>標簽來定位圖片資源的加載位置,因此,我們可以通過此種方式,將KML文件模擬稱為瓦片資源,並在本地模擬一個GIS中的瓦片系統來達到GE脫機使用的需求!

    I.切片:

    1.一般約定,每張瓦片的像素大小爲256*256,從第一級(整個世界一張瓦片),按照比例尺倍增的方式放大,第N級地區的比例尺算法如下:

            1:(20037508.3427892*2*100)/(256/96*2.54)/(2^(N-1))=1: 591658710.90912992125984251968504/(2^(N-1)) 

    2.第N級總像素算法:

    256*(2^(N-1))

    3. 原始數據(longitude and latitude)按墨卡托投影(把地球視為正球體),投影文件如下:

    PROJCS["Google_Mercator",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,0.0]],

    PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Mercator"],PARAMETER["False_Easting",0.0],

     

    PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",0.0],PARAMETER["Standard_Parallel_1",0.0],UNIT["Meter",1.0]]

    4.投影後世界地圖東西向範圍(-20037508.3427892,20037508.3427892 單位:m),南北向忽略變形大的高緯度地區取東西向相同範圍。

    經緯度範圍——東西[-180,180],南北[-85.0511287798065985.05112877980659].

    轉換成瓦片後,第17級像素坐標和經緯度的對應關係可以達到GIS系統要求的精確度,經緯度(dLng,dLat)和17級像素坐標(X,Y)轉換算法:

    dLng = (X * 180.0/16777216-180.0) ;

    dLat  = (atan(exp((Y-16777216)/(-5340353.8065374867)))*2-(PI/2))/PI*180;  

     X     = (int)((dLng + 180)*16777216/180 + 0.5);

     

     Y     = (int)((log(tan((dLat/180*PI+(PI/2))/2)) *(-5340353.8065374867)) +16777216 + 0.5); 

    第N級像素坐標(nX,nY)和第17級像素坐標(X,Y)轉換算法:

    nX = X / (2^(17-N));

    nY = Y / (2^(17-N)); 

    X   = nX*(2^(17-N)); 

     

    Y   = nY*(2^(17-N)); 

    5.瓦片編號規則,按照從西到東自0開始遞增列號,從北到南自0開始遞增行號。

    6.第N級像素坐標(nX,nY)和該點所在行列號(col,row)以及該點所在瓦片上的偏移坐標(dX,dY)的轉換算法:

    nX  = col * 256 + dX;

    nY  = row * 256 + dY;

    col  = nX / 256;

    dX  = nX % 256;

    row = nY / 256;

     

    dY  = nY % 256; 

    通過以上的切片算法描述,我們將瓦片切片後保存!

    II.生成KML文件

    現在我們擁有已經完成切片的瓦片數據,其目錄結構為標準的GIS要求的目錄結構(結構標準:層級/行號/列號 ,例如:L07/R000027/C000050),利用這個目錄結構我們將生成KML文件與文件中對應的瓦片資源存放在同一目錄結構下。

    此時,我們需要自己編寫一個小工具(我用C++寫了一個KML自動生成工具),根據原有的瓦片及其目錄結構來自動生成KML文件,KML文件規範標準如下:

    <name>標簽中爲瓦片資源的文件名,<Icon>標簽下爲瓦片資源路徑,KML文件命名要求與該KML文件中瓦片資源的文件名一致!

     

    III.瓦片加載

    在完成KML文件生成後,我們可以將KML文件看成GIS標準中的瓦片資源,通過加載KML文件來達到GIS中瓦片加載的效果。

     

    1.初始化地球

    以下爲Google官網提供的初始化地球源碼:

    <html><head>
      <title>Sample</title>
      <scripttype="text/javascript"src="https://www.google.com/jsapi"></script>
      <scripttype="text/javascript">
        var ge;
        google.load("earth","1",{"other_params":"sensor=true_or_false"});
    
        function init(){
          google.earth.createInstance('map3d', initCB, failureCB);
        }
    
        function initCB(instance){
          ge = instance;
          ge.getWindow().setVisibility(true);
        }
    
        function failureCB(errorCode){
        }
    
        google.setOnLoadCallback(init);
      </script></head><body>
      <divid="map3d"style="height:400px;width:600px;"></div></body></html>

    在初始化完成後,我們需要在initCB()中添加一個監聽器,來監聽用戶操作事件:

    以上代碼的意義是添加一個viewchanggend事件的監聽器,在用戶觸發事件的500ms後執行LoadTiles方法。

    下面我們具體看一看瓦片加載過程,請原諒我無法公佈完整的源代碼,在此我只公佈一部分比較核心和能體現加載過程算法的源碼:

    我們來解析以下上面的代碼,就能完整的知道瓦片加載的具體過程:

    1.ReleaseResource(); // 釋放以前的資源

    2.var focus=GetCurrentFocus(event);  // 獲取當前焦點經緯坐標包括目前攝像機觀察高度

    3.var pixelCoord17=To17PixelCoordinates(focus);  // 根據當前獲取的焦點經緯坐標將其轉換成為                                                                                   // 對應的第17層級像素坐標

    4.var currentZoomLevel=GetCurrentZoomLevel(focus);  // 獲取當前地圖層級

    5.var currentPixelCoord=CaluCurrentZoomPixelCoord(pixelCoord17,currentZoomLevel);  // 計算當前層級的像素坐標

    6.var currentTile=CaluRowAndCol(currentPixelCoord);   // 計算當前焦點所屬瓦片的行列號

    7.var currentMatrix=ToMatrix(currentTile,2,3);  // 計算瓦片範圍,此處可以根據視窗大小來計                                                                                   // 算,也可以直接製定加載範圍

    8.var levelPath=ProcessLevelPath(currentZoomLevel);  // 處理當前層級對應的文件路徑

    9.var rowPath=ProcessRowPath(currentTile);  // 處理計算出的瓦片行號對應的文件路徑

    10.var colPath=ProcessColPath(currentTile);  // 處理計算出的瓦片列號對應的文件路徑

    經過以上步驟的處理,我們得到了需要加載瓦片的範圍,之後要做的就是加載他們。

    至此,本地模擬瓦片系統就基本已經完成了,我們可以在脫機的情況下使用GE並且可以獲得與聯機時同樣的體驗,在本例子中沒有說明的還有瓦片資源的釋放和防止瓦片重複加載的問題!

  • 相关阅读:
    从万元户到千万富翁:6招助你蜕变
    16款有助于提升工作效率的工具
    8个身家百万的儿童创业者
    关于航模无刷电机发热问题的假想解决方案
    折腾了2个晚上无刷电调(ESC),电机终于转起来了,特此记录一下
    PWM占空比和分辨率(转)
    MSB与LSB(转)
    树莓派3uart wifi模块调试 (浪费了我3天时间的宝贵经验)
    USB加minicom使用串口
    【转】使用BBB的device tree和cape(重新整理版)
  • 原文地址:https://www.cnblogs.com/anders0721/p/3580092.html
Copyright © 2011-2022 走看看