zoukankan      html  css  js  c++  java
  • 揭密Google Map的工作原理

    • 板块:技术
    • 作者:文/ Pascal Buirey 译/Amanda
    • 编者按:我分析了google map的工作原理,特别是如何进行tiles编码。Google map使用预着色tiles,可以通过一个简单的url地址实现。
    • 作者简介:
    • 来源:

      我分析了google map的工作原理,特别是如何进行tiles编码。Google map使用预着色tiles,可以通过一个简单的url地址实现。这篇文章将解释如何从地理坐标(经纬度)建立tile的url地址。


    Map tile编码

      Google map使用两种算法对tile的位置进行编码。

      对于Google map,tile的url地址类似于:http://mt1.google.com/mt?n=404&v=w2.89&x=130&y=93&zoom=9使用x和y来设置tile坐标和放大因子。放大因子从17(完全缩小)到0(最大比例)。当放大因子为17时,整个地球在一个tile中显示,此时x=0 ,y=0;放大因子为16时,地球被分为2x2部分,这时0<=x<=1 且0<=y<=1。每放大一次,每个tile被分为4个部分。因此,当放大因子为z时,显示的水平和垂直tile个数为2^(17-z)。


    算法:寻找经纬度和放大因子


    //correct the latitude to go from 0 (north) to 180 (south),
    // instead of 90(north) to -90(south)
    latitude=90-latitude;

    //correct the longitude to go from 0 to 360
    longitude=180+longitude;

    //find tile size from zoom level
    double latTileSize=180/(pow(2,(17-zoom)));
    double longTileSize=360/(pow(2,(17-zoom)));

    //find the tile coordinates
    int tilex=(int)(longitude/longTileSize);
    int tiley=(int)(latitude/latTileSize);


      事实上,这个算法只是理论上的,覆盖的地带还无法和整个地球匹配。


      服务器:
      Google使用4台服务器维持加载。分别是mt0, mt1, mt2 and mt3。


      显示位置:
      每个tile为256x256 的.png格式的图像。


      对于卫星影像,编码方式有点不同


      Tile的url地址类似于http://kh0.google.com/kh?n=404&v=8&t=trtqtthttp://kh.google.com/kh?v=34&t=trtqtt其中参数t对影像的位置进行编码。参数的长度表示缩放级别。


      t=t时,可观察整个地球,只有一个tile表示地球。下一个放大级别是,该tile被分为4个象限,从左上顺时针开始分别是'q' 'r' 's' 和 't'。在你观察的影像那个象限后添加字母,就可以看见下一级象限。比如,'t=tq'时,给出't' 影像的左上象限。依次类推,可以表示每个缩放级别…


    算法:寻找经纬度和放大因子


     Collapse
    //initialise the variables;
    double xmin=-180;
    double xmax=180;
    double ymin=-90;
    double ymax=90;
    double xmid=0;
    double ymid=0;

    string location="t";

    //google use a latitude divided by 2;
    double halflat = latitude / 2;
    for (int i = 0; i < zoom; i++)
        {
            xmoy = (xmax + xmin) / 2;
            ymoy = (ymax + ymin) / 2;
            if (halflat > ymoy) //upper part (q or r)
                {
                ymin = ymoy;
                if (longitude < xmoy)
                { /*q*/
                    location+= "q";
                    xmax = xmoy;
                }
                else
                {/*r*/
                    location+= "r";
                    xmin = xmoy;
                }
            }
            else //lower part (t or s)
            {
                ymax = ymoy;
                if (longitude < xmoy)
                { /*t*/
                    location+= "t";
                    xmax = xmoy;
                }
                else
                {/*s*/
                    location+= "s";
                    xmin = xmoy;
                }
            }
        }
    //here, the location should contains the string corresponding to the tile...


      同样,这个算法也是理论上的,覆盖地带还无法和整个地球匹配。

      服务器:
      Google使用4台服务器维持加载。分别是kh0, kh1, kh2 and kh3。

      显示位置:
      每个tile为256x256 的.jpg格式图像。

      墨卡托投影

      由于在显示时使用了墨卡托投影,因此上述的算法需要进行修改。在墨卡托投影中,两条纬线间的距离不一定相等,所以描述tile的角度依据它的垂直位置。


    以下代码为从tile的纬度位置计算的tile的垂直个数

     Collapse
    /**<summary>Get the vertical tile number from a latitude using mercator ptrojection formula</summary>*/
            private int getMercatorLatitude(double lati)
            {
                double maxlat = Math.PI;

                double lat = lati;
               
                if (lat > 90) lat = lat - 180;
                if (lat < -90) lat = lat + 180;

                // conversion degre=>radians
                double phi = Math.PI * lat / 180;

                double res;
                //double temp = Math.Tan(Math.PI / 4 - phi / 2);
                //res = Math.Log(temp);
                res = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
                double maxTileY = Math.Pow(2, zoom);
                int result = (int)(((1 - res / maxlat) / 2) * (maxTileY));

                return (result);
            }


      覆盖地带:
      理论上,纬度范围应该是-90度到90度,但事实上,由于墨卡托投影使得两级无穷大,覆盖的地带小于-90 到 90。实际最大的纬度可通过公式Y = 1/2((1+sin(lat))/(1-sin(lat)))求得,其中PI =3.1415926。


      保护:
      Google map使用保护机制维持高质量服务。如果某个用户要求太多,Google map将添加它的IP地址到黑名单,并发送一条有意思的消息:

      Google Error


      我们很抱歉... ...您的查询像病毒或黑客应用程序的自动化请求。为了保护我们的用户,现在无法处理您的请求。我们将尽快恢复您的访问,所以请重新试试。同时,如果您怀疑您的计算机或网络被感染了,可以清除病毒。为给您带来的不便表示歉意,希望能在Google上再一次见到您。

      为了避免被列入黑名单,开发员应该使用隐藏机制…

      很有趣吧?

      这里有个用C#写的简单代码:Download GoogleMapSample.zip - 40.4 KB
    注:Google map 改变了地图的参数v,当我写这篇文章时,v为2.12,但现在变为2.43。我觉得这个有点像版本号或其它什么的。

  • 相关阅读:
    预习非数值数据的编码方式
    预习原码补码反码
    C语言||作业01
    C语言寒假大作战04
    关于数据库及druid连接池版本,还有相关配置异常。。。
    关于idea部署web项目出现中文乱码
    spring与mybatis整合
    mybatis使用
    今日异常(7.8):关于maven项目复制问题
    今日异常(7.6):Mybatis错误:There is no getter for property named 'xxx' in 'class java.lang.String'
  • 原文地址:https://www.cnblogs.com/bluespot/p/1399000.html
Copyright © 2011-2022 走看看