天天看點

谷歌地圖解析及ArcEngine加載谷歌地圖方法前言1.簡介2.擷取切片位址3.經緯度與切片的互相轉換4.縮放級别Z的計算5.結束語

谷歌地圖解析及ArcEngine加載谷歌地圖方法

  • 前言
  • 1.簡介
  • 2.擷取切片位址
  • 3.經緯度與切片的互相轉換
  • 4.縮放級别Z的計算
    • 4.1 比例尺比較法
    • 4.2 最大切片數量法
  • 5.結束語

前言

上一章介紹了ArcGIS加載天地圖的方法。然後谷歌地圖确是ArcGIS目前沒有支援的,網上也有一些工具可以添加到ArcMap的toolbox中進而實作加載谷歌地圖。那麼在ArcEngine開發中,該如何實作谷歌地圖的加載呢?具體代碼下載下傳,各位看官可戳這裡

接下來将從實作原理展開介紹

1.簡介

谷歌地圖采用的是web墨卡托投影,坐标系為WGS84坐标系,為了友善忽略了兩極變形較大的地區,把世界地圖做成了一個邊長等于赤道周長的正方形(赤道半徑為6378137米),原點在正方形中心,即經緯度為(0,0)處。Web墨卡托投影的X,Y坐标取值範圍為:[-20037508.3427892,20037508.3427892],對應的經度取值範圍為[-180,180],對應的緯度範圍則為[-85.05112877980659,85.05112877980659]

參考自:Google 地圖切片URL位址解析_GIS 随筆-CSDN部落格

2.擷取切片位址

打開谷歌地圖,位址:http://www.rivermap.cn/google_view.html

谷歌地圖解析及ArcEngine加載谷歌地圖方法前言1.簡介2.擷取切片位址3.經緯度與切片的互相轉換4.縮放級别Z的計算5.結束語

點選F12,通過變化地圖,可在後側NetWork——All中檢測到剛剛的操作通路到的網址,選擇其中一個網址(也可直接輕按兩下打開),在右側PreView可進行切片預覽,點選Header,可獲得該網址的具體資訊(如下所示),其中Request URL即為我們需要下載下傳的切片的位址。

谷歌地圖解析及ArcEngine加載谷歌地圖方法前言1.簡介2.擷取切片位址3.經緯度與切片的互相轉換4.縮放級别Z的計算5.結束語

衆所周知,谷歌系列産品在國内向來不太友好,是以谷歌地圖的切片位址也是有可能變化的,但是萬變不離其中,類型标簽與切片計算方法是基本不變的。

m:路線圖

t:地形圖

p:帶标簽的地形圖

s:衛星圖

y:帶标簽的衛星圖

h:标簽層(路名、地名等)

2020年12月份左右,谷歌地圖的各類位址規則如下

switch (type)
{
    case "地形":
        uri = new Uri($"http://mt3.google.cn/vt/[email protected],[email protected]&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}&s=Galile");
        break;
    case "高程":
        //谷歌電子地圖
        uri = new Uri($"http://mt3.google.cn/vt/[email protected]&hl=zh-CN&gl=CN&src=app&x={x}&y={y}&z={z}&s=Galile");
        break;
    case "影像":
    default:
        uri = new Uri($"http://mt3.google.cn/vt/[email protected]&hl=zh-CN&gl=cn&src=app&s=G&x={x}&y={y}&z={z}");
        break;
}
           

其中,x代表切片的橫坐标,y代表切片的縱坐标,z代表縮放級别,mt3代表切片存儲的伺服器,我嘗試過換成mt0,mt1,mt2結果其實都是一緻的,隻是不同伺服器上的相同切片罷了,猜測谷歌地圖采用的是一種并發通路機制。

然而,到了2021年,在寫這篇博文時發現由于某些原因,谷歌地圖貌似被禁了,通路慢不說(當然也不排除我的網速問題),切片請求位址也發生了變化,但是從下面兩張圖也可以發現,谷歌地圖的通路位址是非常相似的,切換type标簽基本上就夠了,如果切換标簽也無法擷取切片,那麼方法和上述一樣,通路該類型的地圖,用F12擷取切片位址規律

谷歌地圖解析及ArcEngine加載谷歌地圖方法前言1.簡介2.擷取切片位址3.經緯度與切片的互相轉換4.縮放級别Z的計算5.結束語
谷歌地圖解析及ArcEngine加載谷歌地圖方法前言1.簡介2.擷取切片位址3.經緯度與切片的互相轉換4.縮放級别Z的計算5.結束語

3.經緯度與切片的互相轉換

class GoogleTile
{
     public double x { get; set; }
     public double y { get; set; }
     public int z { get; set; }
     /// <summary>
     /// 經緯度轉切片
     /// </summary>
     /// <param name="x"></param>
     /// <param name="y"></param>
     /// <param name="z"></param>
     /// <returns></returns>
     public static GoogleTile XyToTile(double x, double y, int z)
     {
         return new GoogleTile()
         {
             x = LonToX(x, z),
             y = LatToY(y, z),
             z = z
         };
     }
     /// <summary>
     /// 緯度轉切片y
     /// </summary>
     /// <param name="lat"></param>
     /// <param name="zoom"></param>
     /// <returns></returns>
     public static double LatToY(double lat, int zoom)
     {
         return Convert.ToDouble(Math.Floor((1 - Math.Log(Math.Tan(lat * Math.PI / 180) + 1 / Math.Cos(lat * Math.PI / 180)) / Math.PI) / 2 * Math.Pow(2, zoom)));
     }
     /// <summary>
     /// 經度轉切片x
     /// </summary>
     /// <param name="lon"></param>
     /// <param name="zoom"></param>
     /// <returns></returns>
     public static double LonToX(double lon, int zoom)
     {
         return Convert.ToDouble(Math.Floor((lon + 180) / 360 * Math.Pow(2, zoom)));
     }
     /// <summary>
     /// 切片x轉經度
     /// </summary>
     /// <param name="x"></param>
     /// <param name="zoom"></param>
     /// <returns></returns>
     public static double XToLon(double x, int zoom)
     {
         return Convert.ToDouble(x / Math.Pow(2, zoom) * 360 - 180);
     }
     /// <summary>
     /// 切片y轉緯度
     /// </summary>
     /// <param name="y"></param>
     /// <param name="zoom"></param>
     /// <returns></returns>
     public static double YToLat(double y, int zoom)
     {
         return Convert.ToDouble((Math.Atan(Math.Pow(Math.E, (1 - 2 * y / Math.Pow(2, zoom)) * Math.PI)) - Math.PI / 4) * 2 * 180 / Math.PI);

     }
 }
           

4.縮放級别Z的計算

4.1 比例尺比較法

20 : 1128.497220
19 : 2256.994440
18 : 4513.988880
17 : 9027.977761
16 : 18055.955520
15 : 36111.911040
14 : 72223.822090
13 : 144447.644200
12 : 288895.288400
11 : 577790.576700
10 : 1155581.153000
9  : 2311162.307000
8  : 4622324.614000
7  : 9244649.227000
6  : 18489298.450000
5  : 36978596.910000
4  : 73957193.820000
3  : 147914387.600000
2  : 295828775.300000
1  : 591657550.500000
           

上述為arcgis官網提供的谷歌地圖縮放級别與比例尺的關系

參考連結

可通過求目前比例尺與上述數組的內插補點,取最小內插補點對應的縮放級别

4.2 最大切片數量法

采用比例尺比較的方法,确實可以選出合适的切片,實作縮放效果,但是可能會導緻需要加載的切片數量過多,加載緩慢,是以可以通過限制最大切片數量的方法進行加載,具體代碼如下:

private void CalculateZ(ref GoogleTile pmin, ref GoogleTile pmax)
{
    var env = MapControl.ActiveView.Extent;
    //確定是比較的wgs84坐标系的環境
    if (MapControl.SpatialReference.Name != WgsRefer.Name)
    {
        var ref2 = CoorCalculate.GetRefByWkid(4326, true);
        env.Project(ref2);
    }
    for (var i = 22; i >= 0; i--)
    {
        pmin = GoogleTile.XyToTile(env.XMin, env.YMax, (int)i);
        pmax = GoogleTile.XyToTile(env.XMax, env.YMin, (int)i);
        //切片數量不大于3
        if (pmax.y - pmin.y < 3)
            break;
    }
}
           

5.結束語

由于某些原因,谷歌地圖在國内的環境确實不算友好,經常出現無法通路的情況,是以,若是在項目中使用線上地圖,還是建議大家支援國産的地圖,如天地圖,百度地圖等。