GIS理論(墨卡託投影、地理座標系、地面分辨率、地圖比例尺、Bing Maps Tile System)

墨卡託投影(Mercator Projection),又名「等角正軸圓柱投影」,荷蘭地圖學家墨卡託(Mercator)在1569年擬定,假設地球被圍在一箇中空的圓柱裏,其赤道與圓柱相接觸,而後再假想地球中心有一盞燈,把球面上的圖形投影到圓柱體上,再把圓柱體展開,這就是一幅標準緯線爲零度(即赤道)的「墨卡託投影」繪製出的世界地圖。html

         

 

1、墨卡託投影座標系(Mercator Projection)git

  墨卡託投影以整個世界範圍,赤道做爲標準緯線,本初子午線做爲中央經線,二者交點爲座標原點,向東向北爲正,向西向南爲負。南北極在地圖的正下、上方,而東西方向處於地圖的正右、左。算法

  因爲Mercator Projection在兩極附近是趨於無限值得,所以它並沒完整展示了整個世界,地圖上最高緯度是85.05度。爲了簡化計算,咱們採用球形映射,而不是橢球體形狀。雖然採用Mercator Projection只是爲了方便展現地圖,須要知道的是,這種映射會給Y軸方向帶來0.33%的偏差。數據庫

         

 

  因爲赤道半徑爲6378137米,則赤道周長爲2*PI*r = 20037508.3427892,所以X軸的取值範圍:[-20037508.3427892,20037508.3427892]。當緯度φ接近兩極,即90°時,Y值趨向於無窮。所以一般把Y軸的取值範圍也限定在[-20037508.3427892,20037508.3427892]之間。所以在墨卡託投影座標系(米)下的座標範圍是:最小爲(-20037508.3427892, -20037508.3427892 )到最大 座標爲(20037508.3427892, 20037508.3427892)。express

 

2、地理座標系(Geographical coordinates)性能

  地理經度的取值範圍是[-180,180],緯度不可能到達90°,經過緯度取值範圍爲[20037508.3427892,20037508.3427892]反計算可獲得緯度值爲85.05112877980659。所以緯度取值範圍是[-85.05112877980659,85.05112877980659]。所以,地理座標系(經緯度)對應的範圍是:最小地理座標(-180,-85.05112877980659),最大地理座標(180, 85.05112877980659)。優化

 

3、地面分辨率(Ground Resolution)
  地面分辨率是以一個像素(pixel)表明的地面尺寸(米)。以微軟Bing Maps爲例,當Level爲1時,圖片大小爲512*512(4個Tile),那麼赤道空間分辨率爲:赤道周長/512。其餘緯度的空間分辨率則爲 緯度圈長度/512,極端的北極則爲0。Level爲2時,赤道的空間分辨率爲 赤道周長/1024,其餘緯度爲 緯度圈長度1024。很明顯,Ground Resolution取決於兩個參數,縮放級別Level和緯度latitude ,Level決定像素的多少,latitude決定地面距離的長短。ui

  地面分辨率的公式爲,單位:米/像素:編碼

  ground resolution = (cos(latitude * pi/180) * 2 * pi * 6378137 meters) / (256 * 2level pixels)  spa

 

  最低地圖放大級別(1級),地圖是512 x 512像素。每下一個放大級別,地圖的高度和寬度分別乘於2:2級是1024 x 1024像素,3級是2048 x 2048像素,4級是4096 x 4096像素,等等。一般而言,地圖的寬度和高度能夠由如下式子計算獲得:map width = map height = 256 * 2^level pixels

 

4、地圖比例尺(Map Scale)

  地圖比例尺是指測量相同目標時,地圖上距離與實際距離的比例。經過地圖分辨率在計算可知由Level可獲得圖片的像素大小,那麼須要把其轉換爲以米爲單位的距離,涉及到DPI(dot per inch),暫時可理解爲相似的PPI(pixelper inch),即每英寸表明多少個像素。256 * 2level / DPI 即獲得相應的英寸inch,再把英寸inch除以0.0254轉換爲米。實地距離仍舊是:cos(latitude * pi/180) * 2 * pi * 6378137 meters; 所以比例尺的公式爲:

  map scale = 256 * 2level / screen dpi / 0.0254 / (cos(latitude * pi/180) * 2 * pi * 6378137)

  比例尺= 1 : (cos(latitude * pi/180) * 2 * pi * 6378137 * screen dpi) / (256 * 2level * 0.0254)

 

  地面分辨率和地圖比例尺之間的關係:

  map scale = 1 : ground resolution * screen dpi / 0.0254 meters/inch

 

縮放級別

地圖寬度、高度(像素)

地面分辨率(米/像素)

地圖比例尺(以96dpi爲例)

1

512

78,271.5170

1 : 295,829,355.45

2

1,024

39,135.7585

1 : 147,914,677.73

3

2,048

19,567.8792

1 : 73,957,338.86

4

4,096

9,783.9396

1 : 36,978,669.43

5

8,192

4,891.9698

1 : 18,489,334.72

6

16,384

2,445.9849

1 : 9,244,667.36

7

32,768

1,222.9925

1 : 4,622,333.68

8

65,536

611.4962

1 : 2,311,166.84

9

131,072

305.7481

1 : 1,155,583.42

10

262,144

152.8741

1 : 577,791.71

11

524,288

76.4370

1 : 288,895.85

12

1,048,576

38.2185

1 : 144,447.93

13

2,097,152

19.1093

1 : 72,223.96

14

4,194,304

9.5546

1 : 36,111.98

15

8,388,608

4.7773

1 : 18,055.99

16

16,777,216

2.3887

1 : 9,028.00

17

33,554,432

1.1943

1 : 4,514.00

18

67,108,864

0.5972

1 : 2,257.00

19

134,217,728

0.2986

1 : 1,128.50

20

268,435,456

0.1493

1 : 564.25

21

536,870,912

0.0746

1 : 282.12

22

1,073,741,824

0.0373

1 : 141.06

23

2,147,483,648

0.0187

1 : 70.53

 

 

5、Bing Maps像素座標系和地圖圖片編碼

  爲了優化地圖系統性能,提升地圖下載和顯示速度,全部地圖都被分割成256 x 256像素大小的正方形小塊。因爲在每一個放大級別下的像素數量都不同,所以地圖圖片(Tile)的數量也不同。每一個tile都有一個XY座標值,從左上角的(0, 0)至右下角的(2^level–1, 2^level–1)。例如在3級放大級別下,全部tile的座標值範圍爲(0, 0)至(7, 7),以下圖:

        

  已知一個像素的XY座標值時,咱們很容易獲得這個像素所在的Tile的XY座標值:

    tileX = floor(pixelX / 256)  tileY = floor(pixelY / 256)

 

  爲了簡化索引和存儲地圖圖片,每一個tile的二維XY值被轉換成一維字串,即四叉樹鍵值(quardtree key,簡稱quadkey)。每一個quadkey獨立對應某個放大級別下的一個tile,而且它能夠被用做數據庫中B-tree索引值。爲了將座標值轉換成quadkey,須要將Y和X座標二進制值交錯組合,並轉換成4進制值及對應的字符串。例如,假設在放大級別爲3時,tile的XY座標值爲(3,5),quadkey計算以下:

  tileX = 3 = 011(二進制)

  tileY = 5 = 101(二進制)

  quadkey = 100111(二進制) = 213(四進制) = 「213」

  Quadkey還有其餘一些有意思的特性。第一,quadkey的長度等於該tile所對應的放大級別;第二,每一個tile的quadkey的前幾位和其父tile(上一放大級別所對應的tile)的quadkey相同,下圖中,tile 2是tile 20至23的父tile,tile 13是tile 130至133的父級:

      

 

  最後,quadkey提供的一維索引值一般顯示了兩個tile在XY座標系中的類似性。換句話說,兩個相鄰的tile對應的quadkey很是接近。這對於優化數據庫的性能很是重要,由於相鄰的tile一般被同時請求顯示,所以能夠將這些tile存放在相同的磁盤區域中,以減小磁盤的讀取次數。

 

  下面是微軟Bing Maps的TileSystem相關算法:

複製代碼
using  System;
using  System.Text;

namespace  Microsoft.MapPoint
{
    
static   class  TileSystem
    {
        
private   const   double  EarthRadius  =   6378137 ;
        
private   const   double  MinLatitude  =   - 85.05112878 ;
        
private   const   double  MaxLatitude  =   85.05112878 ;
        
private   const   double  MinLongitude  =   - 180 ;
        
private   const   double  MaxLongitude  =   180 ;


        
///   <summary>
        
///  Clips a number to the specified minimum and maximum values.
        
///   </summary>
        
///   <param name="n"> The number to clip. </param>
        
///   <param name="minValue"> Minimum allowable value. </param>
        
///   <param name="maxValue"> Maximum allowable value. </param>
        
///   <returns> The clipped value. </returns>
         private   static   double  Clip( double  n,  double  minValue,  double  maxValue)
        {
            
return  Math.Min(Math.Max(n, minValue), maxValue);
        }
        
        

        
///   <summary>
        
///  Determines the map width and height (in pixels) at a specified level
        
///  of detail.
        
///   </summary>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <returns> The map width and height in pixels. </returns>
         public   static   uint  MapSize( int  levelOfDetail)
        {
            
return  ( uint 256   <<  levelOfDetail;
        }



        
///   <summary>
        
///  Determines the ground resolution (in meters per pixel) at a specified
        
///  latitude and level of detail.
        
///   </summary>
        
///   <param name="latitude"> Latitude (in degrees) at which to measure the
        
///  ground resolution. </param>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <returns> The ground resolution, in meters per pixel. </returns>
         public   static   double  GroundResolution( double  latitude,  int  levelOfDetail)
        {
            latitude 
=  Clip(latitude, MinLatitude, MaxLatitude);
            
return  Math.Cos(latitude  *  Math.PI  /   180 *   2   *  Math.PI  *  EarthRadius  /  MapSize(levelOfDetail);
        }



        
///   <summary>
        
///  Determines the map scale at a specified latitude, level of detail,
        
///  and screen resolution.
        
///   </summary>
        
///   <param name="latitude"> Latitude (in degrees) at which to measure the
        
///  map scale. </param>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <param name="screenDpi"> Resolution of the screen, in dots per inch. </param>
        
///   <returns> The map scale, expressed as the denominator N of the ratio 1 : N. </returns>
         public   static   double  MapScale( double  latitude,  int  levelOfDetail,  int  screenDpi)
        {
            
return  GroundResolution(latitude, levelOfDetail)  *  screenDpi  /   0.0254 ;
        }



        
///   <summary>
        
///  Converts a point from latitude/longitude WGS-84 coordinates (in degrees)
        
///  into pixel XY coordinates at a specified level of detail.
        
///   </summary>
        
///   <param name="latitude"> Latitude of the point, in degrees. </param>
        
///   <param name="longitude"> Longitude of the point, in degrees. </param>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <param name="pixelX"> Output parameter receiving the X coordinate in pixels. </param>
        
///   <param name="pixelY"> Output parameter receiving the Y coordinate in pixels. </param>
         public   static   void  LatLongToPixelXY( double  latitude,  double  longitude,  int  levelOfDetail,  out   int  pixelX,  out   int  pixelY)
        {
            latitude 
=  Clip(latitude, MinLatitude, MaxLatitude);
            longitude 
=  Clip(longitude, MinLongitude, MaxLongitude);

            
double  x  =  (longitude  +   180 /   360
            
double  sinLatitude  =  Math.Sin(latitude  *  Math.PI  /   180 );
            
double  y  =   0.5   -  Math.Log(( 1   +  sinLatitude)  /  ( 1   -  sinLatitude))  /  ( 4   *  Math.PI);

            
uint  mapSize  =  MapSize(levelOfDetail);
            pixelX 
=  ( int ) Clip(x  *  mapSize  +   0.5 0 , mapSize  -   1 );
            pixelY 
=  ( int ) Clip(y  *  mapSize  +   0.5 0 , mapSize  -   1 );
        }



        
///   <summary>
        
///  Converts a pixel from pixel XY coordinates at a specified level of detail
        
///  into latitude/longitude WGS-84 coordinates (in degrees).
        
///   </summary>
        
///   <param name="pixelX"> X coordinate of the point, in pixels. </param>
        
///   <param name="pixelY"> Y coordinates of the point, in pixels. </param>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <param name="latitude"> Output parameter receiving the latitude in degrees. </param>
        
///   <param name="longitude"> Output parameter receiving the longitude in degrees. </param>
         public   static   void  PixelXYToLatLong( int  pixelX,  int  pixelY,  int  levelOfDetail,  out   double  latitude,  out   double  longitude)
        {
            
double  mapSize  =  MapSize(levelOfDetail);
            
double  x  =  (Clip(pixelX,  0 , mapSize  -   1 /  mapSize)  -   0.5 ;
            
double  y  =   0.5   -  (Clip(pixelY,  0 , mapSize  -   1 /  mapSize);

            latitude 
=   90   -   360   *  Math.Atan(Math.Exp( - *   2   *  Math.PI))  /  Math.PI;
            longitude 
=   360   *  x;
        }



        
///   <summary>
        
///  Converts pixel XY coordinates into tile XY coordinates of the tile containing
        
///  the specified pixel.
        
///   </summary>
        
///   <param name="pixelX"> Pixel X coordinate. </param>
        
///   <param name="pixelY"> Pixel Y coordinate. </param>
        
///   <param name="tileX"> Output parameter receiving the tile X coordinate. </param>
        
///   <param name="tileY"> Output parameter receiving the tile Y coordinate. </param>
         public   static   void  PixelXYToTileXY( int  pixelX,  int  pixelY,  out   int  tileX,  out   int  tileY)
        {
            tileX 
=  pixelX  /   256 ;
            tileY 
=  pixelY  /   256 ;
        }



        
///   <summary>
        
///  Converts tile XY coordinates into pixel XY coordinates of the upper-left pixel
        
///  of the specified tile.
        
///   </summary>
        
///   <param name="tileX"> Tile X coordinate. </param>
        
///   <param name="tileY"> Tile Y coordinate. </param>
        
///   <param name="pixelX"> Output parameter receiving the pixel X coordinate. </param>
        
///   <param name="pixelY"> Output parameter receiving the pixel Y coordinate. </param>
         public   static   void  TileXYToPixelXY( int  tileX,  int  tileY,  out   int  pixelX,  out   int  pixelY)
        {
            pixelX 
=  tileX  *   256 ;
            pixelY 
=  tileY  *   256 ;
        }



        
///   <summary>
        
///  Converts tile XY coordinates into a QuadKey at a specified level of detail.
        
///   </summary>
        
///   <param name="tileX"> Tile X coordinate. </param>
        
///   <param name="tileY"> Tile Y coordinate. </param>
        
///   <param name="levelOfDetail"> Level of detail, from 1 (lowest detail)
        
///  to 23 (highest detail). </param>
        
///   <returns> A string containing the QuadKey. </returns>
         public   static   string  TileXYToQuadKey( int  tileX,  int  tileY,  int  levelOfDetail)
        {
            StringBuilder quadKey 
=   new  StringBuilder();
            
for  ( int  i  =  levelOfDetail; i  >   0 ; i -- )
            {
                
char  digit  =   ' 0 ' ;
                
int  mask  =   1   <<  (i  -   1 );
                
if  ((tileX  &  mask)  !=   0 )
                {
                    digit
++ ;
                }
                
if  ((tileY  &  mask)  !=   0 )
                {
                    digit
++ ;
                    digit
++ ;
                }
                quadKey.Append(digit);
            }
            
return  quadKey.ToString();
        }



        
///   <summary>
        
///  Converts a QuadKey into tile XY coordinates.
        
///   </summary>
        
///   <param name="quadKey"> QuadKey of the tile. </param>
        
///   <param name="tileX"> Output parameter receiving the tile X coordinate. </param>
        
///   <param name="tileY"> Output parameter receiving the tile Y coordinate. </param>
        
///   <param name="levelOfDetail"> Output parameter receiving the level of detail. </param>
         public   static   void  QuadKeyToTileXY( string  quadKey,  out   int  tileX,  out   int  tileY,  out   int  levelOfDetail)
        {
            tileX 
=  tileY  =   0 ;
            levelOfDetail 
=  quadKey.Length;
            
for  ( int  i  =  levelOfDetail; i  >   0 ; i -- )
            {
                
int  mask  =   1   <<  (i  -   1 );
                
switch  (quadKey[levelOfDetail  -  i])
                {
                    
case   ' 0 ' :
                        
break ;

                    
case   ' 1 ' :
                        tileX 
|=  mask;
                        
break ;

                    
case   ' 2 ' :
                        tileY 
|=  mask;
                        
break ;

                    
case   ' 3 ' :
                        tileX 
|=  mask;
                        tileY 
|=  mask;
                        
break ;

                    
default :
                        
throw   new  ArgumentException( " Invalid QuadKey digit sequence. " );
                }
            }
        }
    }
}
複製代碼

 

 

  注:本文中內容來源於互聯網整理而成,如涉及到任何侵權等行爲請聯繫本人。

 

  推薦資源:

  《Bing Maps Tile System》

 

轉載自http://www.cnblogs.com/beniao/archive/2010/04/18/1714544.html

相關文章
相關標籤/搜索